blob: 10018135e021f1ffed983554dd9110e3e76455ea [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"
25#include "net/dcsctp/packet/chunk/abort_chunk.h"
26#include "net/dcsctp/packet/chunk/chunk.h"
27#include "net/dcsctp/packet/chunk/cookie_ack_chunk.h"
28#include "net/dcsctp/packet/chunk/cookie_echo_chunk.h"
29#include "net/dcsctp/packet/chunk/data_chunk.h"
30#include "net/dcsctp/packet/chunk/data_common.h"
31#include "net/dcsctp/packet/chunk/error_chunk.h"
32#include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
33#include "net/dcsctp/packet/chunk/forward_tsn_common.h"
34#include "net/dcsctp/packet/chunk/heartbeat_ack_chunk.h"
35#include "net/dcsctp/packet/chunk/heartbeat_request_chunk.h"
36#include "net/dcsctp/packet/chunk/idata_chunk.h"
37#include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h"
38#include "net/dcsctp/packet/chunk/init_ack_chunk.h"
39#include "net/dcsctp/packet/chunk/init_chunk.h"
40#include "net/dcsctp/packet/chunk/reconfig_chunk.h"
41#include "net/dcsctp/packet/chunk/sack_chunk.h"
42#include "net/dcsctp/packet/chunk/shutdown_ack_chunk.h"
43#include "net/dcsctp/packet/chunk/shutdown_chunk.h"
44#include "net/dcsctp/packet/chunk/shutdown_complete_chunk.h"
45#include "net/dcsctp/packet/chunk_validators.h"
46#include "net/dcsctp/packet/data.h"
47#include "net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.h"
48#include "net/dcsctp/packet/error_cause/error_cause.h"
49#include "net/dcsctp/packet/error_cause/no_user_data_cause.h"
50#include "net/dcsctp/packet/error_cause/out_of_resource_error_cause.h"
51#include "net/dcsctp/packet/error_cause/protocol_violation_cause.h"
52#include "net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h"
53#include "net/dcsctp/packet/error_cause/user_initiated_abort_cause.h"
54#include "net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h"
55#include "net/dcsctp/packet/parameter/parameter.h"
56#include "net/dcsctp/packet/parameter/state_cookie_parameter.h"
57#include "net/dcsctp/packet/parameter/supported_extensions_parameter.h"
58#include "net/dcsctp/packet/sctp_packet.h"
59#include "net/dcsctp/packet/tlv_trait.h"
60#include "net/dcsctp/public/dcsctp_message.h"
61#include "net/dcsctp/public/dcsctp_options.h"
62#include "net/dcsctp/public/dcsctp_socket.h"
63#include "net/dcsctp/public/packet_observer.h"
64#include "net/dcsctp/rx/data_tracker.h"
65#include "net/dcsctp/rx/reassembly_queue.h"
66#include "net/dcsctp/socket/callback_deferrer.h"
67#include "net/dcsctp/socket/capabilities.h"
68#include "net/dcsctp/socket/heartbeat_handler.h"
69#include "net/dcsctp/socket/state_cookie.h"
70#include "net/dcsctp/socket/stream_reset_handler.h"
71#include "net/dcsctp/socket/transmission_control_block.h"
72#include "net/dcsctp/timer/timer.h"
73#include "net/dcsctp/tx/retransmission_queue.h"
74#include "net/dcsctp/tx/send_queue.h"
75#include "rtc_base/checks.h"
76#include "rtc_base/logging.h"
77#include "rtc_base/strings/string_builder.h"
78#include "rtc_base/strings/string_format.h"
79
80namespace dcsctp {
81namespace {
82
83// https://tools.ietf.org/html/rfc4960#section-5.1
84constexpr uint32_t kMinVerificationTag = 1;
85constexpr uint32_t kMaxVerificationTag = std::numeric_limits<uint32_t>::max();
86
87// https://tools.ietf.org/html/rfc4960#section-3.3.2
88constexpr uint32_t kMinInitialTsn = 0;
89constexpr uint32_t kMaxInitialTsn = std::numeric_limits<uint32_t>::max();
90
91Capabilities GetCapabilities(const DcSctpOptions& options,
92 const Parameters& parameters) {
93 Capabilities capabilities;
94 absl::optional<SupportedExtensionsParameter> supported_extensions =
95 parameters.get<SupportedExtensionsParameter>();
96
97 if (options.enable_partial_reliability) {
98 capabilities.partial_reliability =
99 parameters.get<ForwardTsnSupportedParameter>().has_value();
100 if (supported_extensions.has_value()) {
101 capabilities.partial_reliability |=
102 supported_extensions->supports(ForwardTsnChunk::kType);
103 }
104 }
105
106 if (options.enable_message_interleaving && supported_extensions.has_value()) {
107 capabilities.message_interleaving =
108 supported_extensions->supports(IDataChunk::kType) &&
109 supported_extensions->supports(IForwardTsnChunk::kType);
110 }
111 if (supported_extensions.has_value() &&
112 supported_extensions->supports(ReConfigChunk::kType)) {
113 capabilities.reconfig = true;
114 }
115 return capabilities;
116}
117
118void AddCapabilityParameters(const DcSctpOptions& options,
119 Parameters::Builder& builder) {
120 std::vector<uint8_t> chunk_types = {ReConfigChunk::kType};
121
122 if (options.enable_partial_reliability) {
123 builder.Add(ForwardTsnSupportedParameter());
124 chunk_types.push_back(ForwardTsnChunk::kType);
125 }
126 if (options.enable_message_interleaving) {
127 chunk_types.push_back(IDataChunk::kType);
128 chunk_types.push_back(IForwardTsnChunk::kType);
129 }
130 builder.Add(SupportedExtensionsParameter(std::move(chunk_types)));
131}
132
133TieTag MakeTieTag(DcSctpSocketCallbacks& cb) {
134 uint32_t tie_tag_upper =
135 cb.GetRandomInt(0, std::numeric_limits<uint32_t>::max());
136 uint32_t tie_tag_lower =
137 cb.GetRandomInt(1, std::numeric_limits<uint32_t>::max());
138 return TieTag(static_cast<uint64_t>(tie_tag_upper) << 32 |
139 static_cast<uint64_t>(tie_tag_lower));
140}
Victor Boivief4fa1662021-09-24 23:01:21 +0200141
142SctpImplementation DeterminePeerImplementation(
143 rtc::ArrayView<const uint8_t> cookie) {
144 if (cookie.size() > 8) {
145 absl::string_view magic(reinterpret_cast<const char*>(cookie.data()), 8);
146 if (magic == "dcSCTP00") {
147 return SctpImplementation::kDcsctp;
148 }
149 if (magic == "KAME-BSD") {
150 return SctpImplementation::kUsrSctp;
151 }
152 }
153 return SctpImplementation::kOther;
154}
Victor Boivieb6580cc2021-04-08 09:56:59 +0200155} // namespace
156
157DcSctpSocket::DcSctpSocket(absl::string_view log_prefix,
158 DcSctpSocketCallbacks& callbacks,
159 std::unique_ptr<PacketObserver> packet_observer,
160 const DcSctpOptions& options)
161 : log_prefix_(std::string(log_prefix) + ": "),
162 packet_observer_(std::move(packet_observer)),
163 options_(options),
164 callbacks_(callbacks),
165 timer_manager_([this]() { return callbacks_.CreateTimeout(); }),
166 t1_init_(timer_manager_.CreateTimer(
167 "t1-init",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200168 absl::bind_front(&DcSctpSocket::OnInitTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200169 TimerOptions(options.t1_init_timeout,
170 TimerBackoffAlgorithm::kExponential,
171 options.max_init_retransmits))),
172 t1_cookie_(timer_manager_.CreateTimer(
173 "t1-cookie",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200174 absl::bind_front(&DcSctpSocket::OnCookieTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200175 TimerOptions(options.t1_cookie_timeout,
176 TimerBackoffAlgorithm::kExponential,
177 options.max_init_retransmits))),
178 t2_shutdown_(timer_manager_.CreateTimer(
179 "t2-shutdown",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200180 absl::bind_front(&DcSctpSocket::OnShutdownTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200181 TimerOptions(options.t2_shutdown_timeout,
182 TimerBackoffAlgorithm::kExponential,
183 options.max_retransmissions))),
Victor Boivieabf61882021-08-12 15:57:49 +0200184 packet_sender_(callbacks_,
185 absl::bind_front(&DcSctpSocket::OnSentPacket, this)),
Victor Boiviebd9031b2021-05-26 19:48:55 +0200186 send_queue_(
187 log_prefix_,
188 options_.max_send_buffer_size,
Victor Boivie236ac502021-05-20 19:34:18 +0200189 [this](StreamID stream_id) {
190 callbacks_.OnBufferedAmountLow(stream_id);
191 },
192 options_.total_buffered_amount_low_threshold,
193 [this]() { callbacks_.OnTotalBufferedAmountLow(); }) {}
Victor Boivieb6580cc2021-04-08 09:56:59 +0200194
195std::string DcSctpSocket::log_prefix() const {
196 return log_prefix_ + "[" + std::string(ToString(state_)) + "] ";
197}
198
199bool DcSctpSocket::IsConsistent() const {
Victor Boivie54e4e352021-09-15 10:42:26 +0200200 if (tcb_ != nullptr && tcb_->reassembly_queue().HasMessages()) {
201 return false;
202 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200203 switch (state_) {
204 case State::kClosed:
205 return (tcb_ == nullptr && !t1_init_->is_running() &&
206 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
207 case State::kCookieWait:
208 return (tcb_ == nullptr && t1_init_->is_running() &&
209 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
210 case State::kCookieEchoed:
211 return (tcb_ != nullptr && !t1_init_->is_running() &&
212 t1_cookie_->is_running() && !t2_shutdown_->is_running() &&
Victor Boiviec20f1562021-06-16 12:52:42 +0200213 tcb_->has_cookie_echo_chunk());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200214 case State::kEstablished:
215 return (tcb_ != nullptr && !t1_init_->is_running() &&
216 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
217 case State::kShutdownPending:
218 return (tcb_ != nullptr && !t1_init_->is_running() &&
219 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
220 case State::kShutdownSent:
221 return (tcb_ != nullptr && !t1_init_->is_running() &&
222 !t1_cookie_->is_running() && t2_shutdown_->is_running());
223 case State::kShutdownReceived:
224 return (tcb_ != nullptr && !t1_init_->is_running() &&
225 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
226 case State::kShutdownAckSent:
227 return (tcb_ != nullptr && !t1_init_->is_running() &&
228 !t1_cookie_->is_running() && t2_shutdown_->is_running());
229 }
230}
231
232constexpr absl::string_view DcSctpSocket::ToString(DcSctpSocket::State state) {
233 switch (state) {
234 case DcSctpSocket::State::kClosed:
235 return "CLOSED";
236 case DcSctpSocket::State::kCookieWait:
237 return "COOKIE_WAIT";
238 case DcSctpSocket::State::kCookieEchoed:
239 return "COOKIE_ECHOED";
240 case DcSctpSocket::State::kEstablished:
241 return "ESTABLISHED";
242 case DcSctpSocket::State::kShutdownPending:
243 return "SHUTDOWN_PENDING";
244 case DcSctpSocket::State::kShutdownSent:
245 return "SHUTDOWN_SENT";
246 case DcSctpSocket::State::kShutdownReceived:
247 return "SHUTDOWN_RECEIVED";
248 case DcSctpSocket::State::kShutdownAckSent:
249 return "SHUTDOWN_ACK_SENT";
250 }
251}
252
253void DcSctpSocket::SetState(State state, absl::string_view reason) {
254 if (state_ != state) {
255 RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Socket state changed from "
256 << ToString(state_) << " to " << ToString(state)
257 << " due to " << reason;
258 state_ = state;
259 }
260}
261
262void DcSctpSocket::SendInit() {
263 Parameters::Builder params_builder;
264 AddCapabilityParameters(options_, params_builder);
265 InitChunk init(/*initiate_tag=*/connect_params_.verification_tag,
266 /*a_rwnd=*/options_.max_receiver_window_buffer_size,
267 options_.announced_maximum_outgoing_streams,
268 options_.announced_maximum_incoming_streams,
269 connect_params_.initial_tsn, params_builder.Build());
270 SctpPacket::Builder b(VerificationTag(0), options_);
271 b.Add(init);
Victor Boivieabf61882021-08-12 15:57:49 +0200272 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200273}
274
275void DcSctpSocket::MakeConnectionParameters() {
276 VerificationTag new_verification_tag(
277 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
278 TSN initial_tsn(callbacks_.GetRandomInt(kMinInitialTsn, kMaxInitialTsn));
279 connect_params_.initial_tsn = initial_tsn;
280 connect_params_.verification_tag = new_verification_tag;
281}
282
283void DcSctpSocket::Connect() {
Victor Boivie15a0c882021-09-28 21:38:34 +0200284 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
285
Victor Boivieb6580cc2021-04-08 09:56:59 +0200286 if (state_ == State::kClosed) {
287 MakeConnectionParameters();
288 RTC_DLOG(LS_INFO)
289 << log_prefix()
290 << rtc::StringFormat(
291 "Connecting. my_verification_tag=%08x, my_initial_tsn=%u",
292 *connect_params_.verification_tag, *connect_params_.initial_tsn);
293 SendInit();
294 t1_init_->Start();
295 SetState(State::kCookieWait, "Connect called");
296 } else {
297 RTC_DLOG(LS_WARNING) << log_prefix()
298 << "Called Connect on a socket that is not closed";
299 }
300 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200301}
302
Sergey Sukhanov43972812021-09-17 15:32:48 +0200303void DcSctpSocket::RestoreFromState(const DcSctpSocketHandoverState& state) {
Victor Boivie15a0c882021-09-28 21:38:34 +0200304 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
305
Sergey Sukhanov43972812021-09-17 15:32:48 +0200306 if (state_ != State::kClosed) {
307 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
308 "Only closed socket can be restored from state");
309 } else {
310 if (state.socket_state ==
311 DcSctpSocketHandoverState::SocketState::kConnected) {
312 VerificationTag my_verification_tag =
313 VerificationTag(state.my_verification_tag);
314 connect_params_.verification_tag = my_verification_tag;
315
316 Capabilities capabilities;
317 capabilities.partial_reliability = state.capabilities.partial_reliability;
318 capabilities.message_interleaving =
319 state.capabilities.message_interleaving;
320 capabilities.reconfig = state.capabilities.reconfig;
321
Sergey Sukhanov72435322021-09-21 13:31:09 +0200322 send_queue_.RestoreFromState(state);
323
Sergey Sukhanov43972812021-09-17 15:32:48 +0200324 tcb_ = std::make_unique<TransmissionControlBlock>(
325 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
326 send_queue_, my_verification_tag, TSN(state.my_initial_tsn),
327 VerificationTag(state.peer_verification_tag),
328 TSN(state.peer_initial_tsn), static_cast<size_t>(0),
329 TieTag(state.tie_tag), packet_sender_,
330 [this]() { return state_ == State::kEstablished; }, &state);
331 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Created peer TCB from state: "
332 << tcb_->ToString();
333
334 SetState(State::kEstablished, "restored from handover state");
335 callbacks_.OnConnected();
336 }
337 }
338
339 RTC_DCHECK(IsConsistent());
Sergey Sukhanov43972812021-09-17 15:32:48 +0200340}
341
Victor Boivieb6580cc2021-04-08 09:56:59 +0200342void DcSctpSocket::Shutdown() {
Victor Boivie15a0c882021-09-28 21:38:34 +0200343 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
344
Victor Boivieb6580cc2021-04-08 09:56:59 +0200345 if (tcb_ != nullptr) {
346 // https://tools.ietf.org/html/rfc4960#section-9.2
347 // "Upon receipt of the SHUTDOWN primitive from its upper layer, the
348 // endpoint enters the SHUTDOWN-PENDING state and remains there until all
349 // outstanding data has been acknowledged by its peer."
Victor Boivie50a0b122021-05-06 21:07:49 +0200350
351 // TODO(webrtc:12739): Remove this check, as it just hides the problem that
352 // the socket can transition from ShutdownSent to ShutdownPending, or
353 // ShutdownAckSent to ShutdownPending which is illegal.
354 if (state_ != State::kShutdownSent && state_ != State::kShutdownAckSent) {
355 SetState(State::kShutdownPending, "Shutdown called");
356 t1_init_->Stop();
357 t1_cookie_->Stop();
358 MaybeSendShutdownOrAck();
359 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200360 } else {
361 // Connection closed before even starting to connect, or during the initial
362 // connection phase. There is no outstanding data, so the socket can just
363 // be closed (stopping any connection timers, if any), as this is the
364 // client's intention, by calling Shutdown.
365 InternalClose(ErrorKind::kNoError, "");
366 }
367 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200368}
369
370void DcSctpSocket::Close() {
Victor Boivie15a0c882021-09-28 21:38:34 +0200371 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
372
Victor Boivieb6580cc2021-04-08 09:56:59 +0200373 if (state_ != State::kClosed) {
374 if (tcb_ != nullptr) {
375 SctpPacket::Builder b = tcb_->PacketBuilder();
376 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
377 Parameters::Builder()
378 .Add(UserInitiatedAbortCause("Close called"))
379 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +0200380 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200381 }
382 InternalClose(ErrorKind::kNoError, "");
383 } else {
384 RTC_DLOG(LS_INFO) << log_prefix() << "Called Close on a closed socket";
385 }
386 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200387}
388
389void DcSctpSocket::CloseConnectionBecauseOfTooManyTransmissionErrors() {
Victor Boivieabf61882021-08-12 15:57:49 +0200390 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200391 true, Parameters::Builder()
392 .Add(UserInitiatedAbortCause("Too many retransmissions"))
393 .Build())));
394 InternalClose(ErrorKind::kTooManyRetries, "Too many retransmissions");
395}
396
397void DcSctpSocket::InternalClose(ErrorKind error, absl::string_view message) {
398 if (state_ != State::kClosed) {
399 t1_init_->Stop();
400 t1_cookie_->Stop();
401 t2_shutdown_->Stop();
402 tcb_ = nullptr;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200403
404 if (error == ErrorKind::kNoError) {
405 callbacks_.OnClosed();
406 } else {
407 callbacks_.OnAborted(error, message);
408 }
409 SetState(State::kClosed, message);
410 }
411 // This method's purpose is to abort/close and make it consistent by ensuring
412 // that e.g. all timers really are stopped.
413 RTC_DCHECK(IsConsistent());
414}
415
416SendStatus DcSctpSocket::Send(DcSctpMessage message,
417 const SendOptions& send_options) {
Victor Boivie15a0c882021-09-28 21:38:34 +0200418 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
419
Victor Boivieb6580cc2021-04-08 09:56:59 +0200420 if (message.payload().empty()) {
421 callbacks_.OnError(ErrorKind::kProtocolViolation,
422 "Unable to send empty message");
423 return SendStatus::kErrorMessageEmpty;
424 }
425 if (message.payload().size() > options_.max_message_size) {
426 callbacks_.OnError(ErrorKind::kProtocolViolation,
427 "Unable to send too large message");
428 return SendStatus::kErrorMessageTooLarge;
429 }
430 if (state_ == State::kShutdownPending || state_ == State::kShutdownSent ||
431 state_ == State::kShutdownReceived || state_ == State::kShutdownAckSent) {
432 // https://tools.ietf.org/html/rfc4960#section-9.2
433 // "An endpoint should reject any new data request from its upper layer
434 // if it is in the SHUTDOWN-PENDING, SHUTDOWN-SENT, SHUTDOWN-RECEIVED, or
435 // SHUTDOWN-ACK-SENT state."
436 callbacks_.OnError(ErrorKind::kWrongSequence,
437 "Unable to send message as the socket is shutting down");
438 return SendStatus::kErrorShuttingDown;
439 }
440 if (send_queue_.IsFull()) {
441 callbacks_.OnError(ErrorKind::kResourceExhaustion,
442 "Unable to send message as the send queue is full");
443 return SendStatus::kErrorResourceExhaustion;
444 }
445
Victor Boivied3b186e2021-05-05 16:22:29 +0200446 TimeMs now = callbacks_.TimeMillis();
Victor Boivied4716ea2021-08-09 12:26:32 +0200447 ++metrics_.tx_messages_count;
Victor Boivied3b186e2021-05-05 16:22:29 +0200448 send_queue_.Add(now, std::move(message), send_options);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200449 if (tcb_ != nullptr) {
Victor Boivied3b186e2021-05-05 16:22:29 +0200450 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200451 }
452
453 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200454 return SendStatus::kSuccess;
455}
456
457ResetStreamsStatus DcSctpSocket::ResetStreams(
458 rtc::ArrayView<const StreamID> outgoing_streams) {
Victor Boivie15a0c882021-09-28 21:38:34 +0200459 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
460
Victor Boivieb6580cc2021-04-08 09:56:59 +0200461 if (tcb_ == nullptr) {
462 callbacks_.OnError(ErrorKind::kWrongSequence,
463 "Can't reset streams as the socket is not connected");
464 return ResetStreamsStatus::kNotConnected;
465 }
466 if (!tcb_->capabilities().reconfig) {
467 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
468 "Can't reset streams as the peer doesn't support it");
469 return ResetStreamsStatus::kNotSupported;
470 }
471
472 tcb_->stream_reset_handler().ResetStreams(outgoing_streams);
473 absl::optional<ReConfigChunk> reconfig =
474 tcb_->stream_reset_handler().MakeStreamResetRequest();
475 if (reconfig.has_value()) {
476 SctpPacket::Builder builder = tcb_->PacketBuilder();
477 builder.Add(*reconfig);
Victor Boivieabf61882021-08-12 15:57:49 +0200478 packet_sender_.Send(builder);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200479 }
480
481 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200482 return ResetStreamsStatus::kPerformed;
483}
484
485SocketState DcSctpSocket::state() const {
486 switch (state_) {
487 case State::kClosed:
488 return SocketState::kClosed;
489 case State::kCookieWait:
490 ABSL_FALLTHROUGH_INTENDED;
491 case State::kCookieEchoed:
492 return SocketState::kConnecting;
493 case State::kEstablished:
494 return SocketState::kConnected;
495 case State::kShutdownPending:
496 ABSL_FALLTHROUGH_INTENDED;
497 case State::kShutdownSent:
498 ABSL_FALLTHROUGH_INTENDED;
499 case State::kShutdownReceived:
500 ABSL_FALLTHROUGH_INTENDED;
501 case State::kShutdownAckSent:
502 return SocketState::kShuttingDown;
503 }
504}
505
Florent Castelli0810b052021-05-04 20:12:52 +0200506void DcSctpSocket::SetMaxMessageSize(size_t max_message_size) {
507 options_.max_message_size = max_message_size;
508}
509
Victor Boivie236ac502021-05-20 19:34:18 +0200510size_t DcSctpSocket::buffered_amount(StreamID stream_id) const {
511 return send_queue_.buffered_amount(stream_id);
512}
513
514size_t DcSctpSocket::buffered_amount_low_threshold(StreamID stream_id) const {
515 return send_queue_.buffered_amount_low_threshold(stream_id);
516}
517
518void DcSctpSocket::SetBufferedAmountLowThreshold(StreamID stream_id,
519 size_t bytes) {
520 send_queue_.SetBufferedAmountLowThreshold(stream_id, bytes);
521}
522
Victor Boivied4716ea2021-08-09 12:26:32 +0200523Metrics DcSctpSocket::GetMetrics() const {
524 Metrics metrics = metrics_;
525
526 if (tcb_ != nullptr) {
527 // Update the metrics with some stats that are extracted from
528 // sub-components.
529 metrics.cwnd_bytes = tcb_->cwnd();
530 metrics.srtt_ms = tcb_->current_srtt().value();
531 size_t packet_payload_size =
532 options_.mtu - SctpPacket::kHeaderSize - DataChunk::kHeaderSize;
533 metrics.unack_data_count =
534 tcb_->retransmission_queue().outstanding_items() +
535 (send_queue_.total_buffered_amount() + packet_payload_size - 1) /
536 packet_payload_size;
537 metrics.peer_rwnd_bytes = tcb_->retransmission_queue().rwnd();
538 }
539
540 return metrics;
541}
542
Victor Boivieb6580cc2021-04-08 09:56:59 +0200543void DcSctpSocket::MaybeSendShutdownOnPacketReceived(const SctpPacket& packet) {
544 if (state_ == State::kShutdownSent) {
545 bool has_data_chunk =
546 std::find_if(packet.descriptors().begin(), packet.descriptors().end(),
547 [](const SctpPacket::ChunkDescriptor& descriptor) {
548 return descriptor.type == DataChunk::kType;
549 }) != packet.descriptors().end();
550 if (has_data_chunk) {
551 // https://tools.ietf.org/html/rfc4960#section-9.2
552 // "While in the SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately
553 // respond to each received packet containing one or more DATA chunks with
554 // a SHUTDOWN chunk and restart the T2-shutdown timer.""
555 SendShutdown();
556 t2_shutdown_->set_duration(tcb_->current_rto());
557 t2_shutdown_->Start();
558 }
559 }
560}
561
562bool DcSctpSocket::ValidatePacket(const SctpPacket& packet) {
563 const CommonHeader& header = packet.common_header();
564 VerificationTag my_verification_tag =
565 tcb_ != nullptr ? tcb_->my_verification_tag() : VerificationTag(0);
566
567 if (header.verification_tag == VerificationTag(0)) {
568 if (packet.descriptors().size() == 1 &&
569 packet.descriptors()[0].type == InitChunk::kType) {
570 // https://tools.ietf.org/html/rfc4960#section-8.5.1
571 // "When an endpoint receives an SCTP packet with the Verification Tag
572 // set to 0, it should verify that the packet contains only an INIT chunk.
573 // Otherwise, the receiver MUST silently discard the packet.""
574 return true;
575 }
576 callbacks_.OnError(
577 ErrorKind::kParseFailed,
578 "Only a single INIT chunk can be present in packets sent on "
579 "verification_tag = 0");
580 return false;
581 }
582
583 if (packet.descriptors().size() == 1 &&
584 packet.descriptors()[0].type == AbortChunk::kType) {
585 // https://tools.ietf.org/html/rfc4960#section-8.5.1
586 // "The receiver of an ABORT MUST accept the packet if the Verification
587 // Tag field of the packet matches its own tag and the T bit is not set OR
588 // if it is set to its peer's tag and the T bit is set in the Chunk Flags.
589 // Otherwise, the receiver MUST silently discard the packet and take no
590 // further action."
591 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
592 if (t_bit && tcb_ == nullptr) {
593 // Can't verify the tag - assume it's okey.
594 return true;
595 }
596 if ((!t_bit && header.verification_tag == my_verification_tag) ||
597 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
598 return true;
599 }
600 callbacks_.OnError(ErrorKind::kParseFailed,
601 "ABORT chunk verification tag was wrong");
602 return false;
603 }
604
605 if (packet.descriptors()[0].type == InitAckChunk::kType) {
606 if (header.verification_tag == connect_params_.verification_tag) {
607 return true;
608 }
609 callbacks_.OnError(
610 ErrorKind::kParseFailed,
611 rtc::StringFormat(
612 "Packet has invalid verification tag: %08x, expected %08x",
613 *header.verification_tag, *connect_params_.verification_tag));
614 return false;
615 }
616
617 if (packet.descriptors()[0].type == CookieEchoChunk::kType) {
618 // Handled in chunk handler (due to RFC 4960, section 5.2.4).
619 return true;
620 }
621
622 if (packet.descriptors().size() == 1 &&
623 packet.descriptors()[0].type == ShutdownCompleteChunk::kType) {
624 // https://tools.ietf.org/html/rfc4960#section-8.5.1
625 // "The receiver of a SHUTDOWN COMPLETE shall accept the packet if the
626 // Verification Tag field of the packet matches its own tag and the T bit is
627 // not set OR if it is set to its peer's tag and the T bit is set in the
628 // Chunk Flags. Otherwise, the receiver MUST silently discard the packet
629 // and take no further action."
630 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
631 if (t_bit && tcb_ == nullptr) {
632 // Can't verify the tag - assume it's okey.
633 return true;
634 }
635 if ((!t_bit && header.verification_tag == my_verification_tag) ||
636 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
637 return true;
638 }
639 callbacks_.OnError(ErrorKind::kParseFailed,
640 "SHUTDOWN_COMPLETE chunk verification tag was wrong");
641 return false;
642 }
643
644 // https://tools.ietf.org/html/rfc4960#section-8.5
645 // "When receiving an SCTP packet, the endpoint MUST ensure that the value
646 // in the Verification Tag field of the received SCTP packet matches its own
647 // tag. If the received Verification Tag value does not match the receiver's
648 // own tag value, the receiver shall silently discard the packet and shall not
649 // process it any further..."
650 if (header.verification_tag == my_verification_tag) {
651 return true;
652 }
653
654 callbacks_.OnError(
655 ErrorKind::kParseFailed,
656 rtc::StringFormat(
657 "Packet has invalid verification tag: %08x, expected %08x",
658 *header.verification_tag, *my_verification_tag));
659 return false;
660}
661
662void DcSctpSocket::HandleTimeout(TimeoutID timeout_id) {
Victor Boivie15a0c882021-09-28 21:38:34 +0200663 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
664
Victor Boivieb6580cc2021-04-08 09:56:59 +0200665 timer_manager_.HandleTimeout(timeout_id);
666
667 if (tcb_ != nullptr && tcb_->HasTooManyTxErrors()) {
668 // Tearing down the TCB has to be done outside the handlers.
669 CloseConnectionBecauseOfTooManyTransmissionErrors();
670 }
671
672 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200673}
674
675void DcSctpSocket::ReceivePacket(rtc::ArrayView<const uint8_t> data) {
Victor Boivie15a0c882021-09-28 21:38:34 +0200676 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
677
Victor Boivied4716ea2021-08-09 12:26:32 +0200678 ++metrics_.rx_packets_count;
679
Victor Boivieb6580cc2021-04-08 09:56:59 +0200680 if (packet_observer_ != nullptr) {
681 packet_observer_->OnReceivedPacket(callbacks_.TimeMillis(), data);
682 }
683
684 absl::optional<SctpPacket> packet =
685 SctpPacket::Parse(data, options_.disable_checksum_verification);
686 if (!packet.has_value()) {
687 // https://tools.ietf.org/html/rfc4960#section-6.8
688 // "The default procedure for handling invalid SCTP packets is to
689 // silently discard them."
690 callbacks_.OnError(ErrorKind::kParseFailed,
691 "Failed to parse received SCTP packet");
692 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200693 return;
694 }
695
696 if (RTC_DLOG_IS_ON) {
697 for (const auto& descriptor : packet->descriptors()) {
698 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received "
699 << DebugConvertChunkToString(descriptor.data);
700 }
701 }
702
703 if (!ValidatePacket(*packet)) {
704 RTC_DLOG(LS_VERBOSE) << log_prefix()
705 << "Packet failed verification tag check - dropping";
706 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200707 return;
708 }
709
710 MaybeSendShutdownOnPacketReceived(*packet);
711
712 for (const auto& descriptor : packet->descriptors()) {
713 if (!Dispatch(packet->common_header(), descriptor)) {
714 break;
715 }
716 }
717
718 if (tcb_ != nullptr) {
719 tcb_->data_tracker().ObservePacketEnd();
720 tcb_->MaybeSendSack();
721 }
722
723 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200724}
725
726void DcSctpSocket::DebugPrintOutgoing(rtc::ArrayView<const uint8_t> payload) {
727 auto packet = SctpPacket::Parse(payload);
728 RTC_DCHECK(packet.has_value());
729
730 for (const auto& desc : packet->descriptors()) {
731 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Sent "
732 << DebugConvertChunkToString(desc.data);
733 }
734}
735
736bool DcSctpSocket::Dispatch(const CommonHeader& header,
737 const SctpPacket::ChunkDescriptor& descriptor) {
738 switch (descriptor.type) {
739 case DataChunk::kType:
740 HandleData(header, descriptor);
741 break;
742 case InitChunk::kType:
743 HandleInit(header, descriptor);
744 break;
745 case InitAckChunk::kType:
746 HandleInitAck(header, descriptor);
747 break;
748 case SackChunk::kType:
749 HandleSack(header, descriptor);
750 break;
751 case HeartbeatRequestChunk::kType:
752 HandleHeartbeatRequest(header, descriptor);
753 break;
754 case HeartbeatAckChunk::kType:
755 HandleHeartbeatAck(header, descriptor);
756 break;
757 case AbortChunk::kType:
758 HandleAbort(header, descriptor);
759 break;
760 case ErrorChunk::kType:
761 HandleError(header, descriptor);
762 break;
763 case CookieEchoChunk::kType:
764 HandleCookieEcho(header, descriptor);
765 break;
766 case CookieAckChunk::kType:
767 HandleCookieAck(header, descriptor);
768 break;
769 case ShutdownChunk::kType:
770 HandleShutdown(header, descriptor);
771 break;
772 case ShutdownAckChunk::kType:
773 HandleShutdownAck(header, descriptor);
774 break;
775 case ShutdownCompleteChunk::kType:
776 HandleShutdownComplete(header, descriptor);
777 break;
778 case ReConfigChunk::kType:
779 HandleReconfig(header, descriptor);
780 break;
781 case ForwardTsnChunk::kType:
782 HandleForwardTsn(header, descriptor);
783 break;
784 case IDataChunk::kType:
785 HandleIData(header, descriptor);
786 break;
787 case IForwardTsnChunk::kType:
788 HandleForwardTsn(header, descriptor);
789 break;
790 default:
791 return HandleUnrecognizedChunk(descriptor);
792 }
793 return true;
794}
795
796bool DcSctpSocket::HandleUnrecognizedChunk(
797 const SctpPacket::ChunkDescriptor& descriptor) {
798 bool report_as_error = (descriptor.type & 0x40) != 0;
799 bool continue_processing = (descriptor.type & 0x80) != 0;
800 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received unknown chunk: "
801 << static_cast<int>(descriptor.type);
802 if (report_as_error) {
803 rtc::StringBuilder sb;
804 sb << "Received unknown chunk of type: "
805 << static_cast<int>(descriptor.type) << " with report-error bit set";
806 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
807 RTC_DLOG(LS_VERBOSE)
808 << log_prefix()
809 << "Unknown chunk, with type indicating it should be reported.";
810
811 // https://tools.ietf.org/html/rfc4960#section-3.2
812 // "... report in an ERROR chunk using the 'Unrecognized Chunk Type'
813 // cause."
814 if (tcb_ != nullptr) {
815 // Need TCB - this chunk must be sent with a correct verification tag.
Victor Boivieabf61882021-08-12 15:57:49 +0200816 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200817 ErrorChunk(Parameters::Builder()
818 .Add(UnrecognizedChunkTypeCause(std::vector<uint8_t>(
819 descriptor.data.begin(), descriptor.data.end())))
820 .Build())));
821 }
822 }
823 if (!continue_processing) {
824 // https://tools.ietf.org/html/rfc4960#section-3.2
825 // "Stop processing this SCTP packet and discard it, do not process any
826 // further chunks within it."
827 RTC_DLOG(LS_VERBOSE) << log_prefix()
828 << "Unknown chunk, with type indicating not to "
829 "process any further chunks";
830 }
831
832 return continue_processing;
833}
834
835absl::optional<DurationMs> DcSctpSocket::OnInitTimerExpiry() {
836 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_init_->name()
837 << " has expired: " << t1_init_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200838 << "/" << t1_init_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200839 RTC_DCHECK(state_ == State::kCookieWait);
840
841 if (t1_init_->is_running()) {
842 SendInit();
843 } else {
844 InternalClose(ErrorKind::kTooManyRetries, "No INIT_ACK received");
845 }
846 RTC_DCHECK(IsConsistent());
847 return absl::nullopt;
848}
849
850absl::optional<DurationMs> DcSctpSocket::OnCookieTimerExpiry() {
851 // https://tools.ietf.org/html/rfc4960#section-4
852 // "If the T1-cookie timer expires, the endpoint MUST retransmit COOKIE
853 // ECHO and restart the T1-cookie timer without changing state. This MUST
854 // be repeated up to 'Max.Init.Retransmits' times. After that, the endpoint
855 // MUST abort the initialization process and report the error to the SCTP
856 // user."
857 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_cookie_->name()
858 << " has expired: " << t1_cookie_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200859 << "/"
860 << t1_cookie_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200861
862 RTC_DCHECK(state_ == State::kCookieEchoed);
863
864 if (t1_cookie_->is_running()) {
Victor Boiviec20f1562021-06-16 12:52:42 +0200865 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200866 } else {
867 InternalClose(ErrorKind::kTooManyRetries, "No COOKIE_ACK received");
868 }
869
870 RTC_DCHECK(IsConsistent());
871 return absl::nullopt;
872}
873
874absl::optional<DurationMs> DcSctpSocket::OnShutdownTimerExpiry() {
875 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t2_shutdown_->name()
876 << " has expired: " << t2_shutdown_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200877 << "/"
878 << t2_shutdown_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200879
Victor Boivie914925f2021-05-07 11:22:50 +0200880 if (!t2_shutdown_->is_running()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +0200881 // https://tools.ietf.org/html/rfc4960#section-9.2
882 // "An endpoint should limit the number of retransmissions of the SHUTDOWN
883 // chunk to the protocol parameter 'Association.Max.Retrans'. If this
884 // threshold is exceeded, the endpoint should destroy the TCB..."
885
Victor Boivieabf61882021-08-12 15:57:49 +0200886 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200887 AbortChunk(true, Parameters::Builder()
888 .Add(UserInitiatedAbortCause(
889 "Too many retransmissions of SHUTDOWN"))
890 .Build())));
891
892 InternalClose(ErrorKind::kTooManyRetries, "No SHUTDOWN_ACK received");
Victor Boivie914925f2021-05-07 11:22:50 +0200893 RTC_DCHECK(IsConsistent());
894 return absl::nullopt;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200895 }
Victor Boivie914925f2021-05-07 11:22:50 +0200896
897 // https://tools.ietf.org/html/rfc4960#section-9.2
898 // "If the timer expires, the endpoint must resend the SHUTDOWN with the
899 // updated last sequential TSN received from its peer."
900 SendShutdown();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200901 RTC_DCHECK(IsConsistent());
902 return tcb_->current_rto();
903}
904
Victor Boivieabf61882021-08-12 15:57:49 +0200905void DcSctpSocket::OnSentPacket(rtc::ArrayView<const uint8_t> packet,
906 SendPacketStatus status) {
907 // The packet observer is invoked even if the packet was failed to be sent, to
908 // indicate an attempt was made.
Victor Boivieb6580cc2021-04-08 09:56:59 +0200909 if (packet_observer_ != nullptr) {
Victor Boivieabf61882021-08-12 15:57:49 +0200910 packet_observer_->OnSentPacket(callbacks_.TimeMillis(), packet);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200911 }
Victor Boivieabf61882021-08-12 15:57:49 +0200912
913 if (status == SendPacketStatus::kSuccess) {
914 if (RTC_DLOG_IS_ON) {
915 DebugPrintOutgoing(packet);
916 }
917
918 // The heartbeat interval timer is restarted for every sent packet, to
919 // fire when the outgoing channel is inactive.
920 if (tcb_ != nullptr) {
921 tcb_->heartbeat_handler().RestartTimer();
922 }
923
924 ++metrics_.tx_packets_count;
925 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200926}
927
928bool DcSctpSocket::ValidateHasTCB() {
929 if (tcb_ != nullptr) {
930 return true;
931 }
932
933 callbacks_.OnError(
934 ErrorKind::kNotConnected,
935 "Received unexpected commands on socket that is not connected");
936 return false;
937}
938
939void DcSctpSocket::ReportFailedToParseChunk(int chunk_type) {
940 rtc::StringBuilder sb;
941 sb << "Failed to parse chunk of type: " << chunk_type;
942 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
943}
944
945void DcSctpSocket::HandleData(const CommonHeader& header,
946 const SctpPacket::ChunkDescriptor& descriptor) {
947 absl::optional<DataChunk> chunk = DataChunk::Parse(descriptor.data);
948 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
949 HandleDataCommon(*chunk);
950 }
951}
952
953void DcSctpSocket::HandleIData(const CommonHeader& header,
954 const SctpPacket::ChunkDescriptor& descriptor) {
955 absl::optional<IDataChunk> chunk = IDataChunk::Parse(descriptor.data);
956 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
957 HandleDataCommon(*chunk);
958 }
959}
960
961void DcSctpSocket::HandleDataCommon(AnyDataChunk& chunk) {
962 TSN tsn = chunk.tsn();
963 AnyDataChunk::ImmediateAckFlag immediate_ack = chunk.options().immediate_ack;
964 Data data = std::move(chunk).extract();
965
966 if (data.payload.empty()) {
967 // Empty DATA chunks are illegal.
Victor Boivieabf61882021-08-12 15:57:49 +0200968 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200969 ErrorChunk(Parameters::Builder().Add(NoUserDataCause(tsn)).Build())));
970 callbacks_.OnError(ErrorKind::kProtocolViolation,
971 "Received DATA chunk with no user data");
972 return;
973 }
974
975 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Handle DATA, queue_size="
976 << tcb_->reassembly_queue().queued_bytes()
977 << ", water_mark="
978 << tcb_->reassembly_queue().watermark_bytes()
979 << ", full=" << tcb_->reassembly_queue().is_full()
980 << ", above="
981 << tcb_->reassembly_queue().is_above_watermark();
982
983 if (tcb_->reassembly_queue().is_full()) {
984 // If the reassembly queue is full, there is nothing that can be done. The
985 // specification only allows dropping gap-ack-blocks, and that's not
986 // likely to help as the socket has been trying to fill gaps since the
987 // watermark was reached.
Victor Boivieabf61882021-08-12 15:57:49 +0200988 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200989 true, Parameters::Builder().Add(OutOfResourceErrorCause()).Build())));
990 InternalClose(ErrorKind::kResourceExhaustion,
991 "Reassembly Queue is exhausted");
992 return;
993 }
994
995 if (tcb_->reassembly_queue().is_above_watermark()) {
996 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Is above high watermark";
997 // If the reassembly queue is above its high watermark, only accept data
998 // chunks that increase its cumulative ack tsn in an attempt to fill gaps
999 // to deliver messages.
1000 if (!tcb_->data_tracker().will_increase_cum_ack_tsn(tsn)) {
1001 RTC_DLOG(LS_VERBOSE) << log_prefix()
1002 << "Rejected data because of exceeding watermark";
1003 tcb_->data_tracker().ForceImmediateSack();
1004 return;
1005 }
1006 }
1007
1008 if (!tcb_->data_tracker().IsTSNValid(tsn)) {
1009 RTC_DLOG(LS_VERBOSE) << log_prefix()
1010 << "Rejected data because of failing TSN validity";
1011 return;
1012 }
1013
1014 tcb_->data_tracker().Observe(tsn, immediate_ack);
1015 tcb_->reassembly_queue().MaybeResetStreamsDeferred(
1016 tcb_->data_tracker().last_cumulative_acked_tsn());
1017 tcb_->reassembly_queue().Add(tsn, std::move(data));
1018 DeliverReassembledMessages();
1019}
1020
1021void DcSctpSocket::HandleInit(const CommonHeader& header,
1022 const SctpPacket::ChunkDescriptor& descriptor) {
1023 absl::optional<InitChunk> chunk = InitChunk::Parse(descriptor.data);
1024 if (!ValidateParseSuccess(chunk)) {
1025 return;
1026 }
1027
1028 if (chunk->initiate_tag() == VerificationTag(0) ||
1029 chunk->nbr_outbound_streams() == 0 || chunk->nbr_inbound_streams() == 0) {
1030 // https://tools.ietf.org/html/rfc4960#section-3.3.2
1031 // "If the value of the Initiate Tag in a received INIT chunk is found
1032 // to be 0, the receiver MUST treat it as an error and close the
1033 // association by transmitting an ABORT."
1034
1035 // "A receiver of an INIT with the OS value set to 0 SHOULD abort the
1036 // association."
1037
1038 // "A receiver of an INIT with the MIS value of 0 SHOULD abort the
1039 // association."
1040
Victor Boivieabf61882021-08-12 15:57:49 +02001041 packet_sender_.Send(
1042 SctpPacket::Builder(VerificationTag(0), options_)
1043 .Add(AbortChunk(
1044 /*filled_in_verification_tag=*/false,
1045 Parameters::Builder()
1046 .Add(ProtocolViolationCause("INIT malformed"))
1047 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001048 InternalClose(ErrorKind::kProtocolViolation, "Received invalid INIT");
1049 return;
1050 }
1051
1052 if (state_ == State::kShutdownAckSent) {
1053 // https://tools.ietf.org/html/rfc4960#section-9.2
1054 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives an
1055 // INIT chunk (e.g., if the SHUTDOWN COMPLETE was lost) with source and
1056 // destination transport addresses (either in the IP addresses or in the
1057 // INIT chunk) that belong to this association, it should discard the INIT
1058 // chunk and retransmit the SHUTDOWN ACK chunk."
1059 RTC_DLOG(LS_VERBOSE) << log_prefix()
1060 << "Received Init indicating lost ShutdownComplete";
1061 SendShutdownAck();
1062 return;
1063 }
1064
1065 TieTag tie_tag(0);
1066 if (state_ == State::kClosed) {
1067 RTC_DLOG(LS_VERBOSE) << log_prefix()
1068 << "Received Init in closed state (normal)";
1069
1070 MakeConnectionParameters();
1071 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1072 // https://tools.ietf.org/html/rfc4960#section-5.2.1
1073 // "This usually indicates an initialization collision, i.e., each
1074 // endpoint is attempting, at about the same time, to establish an
1075 // association with the other endpoint. Upon receipt of an INIT in the
1076 // COOKIE-WAIT state, an endpoint MUST respond with an INIT ACK using the
1077 // same parameters it sent in its original INIT chunk (including its
1078 // Initiate Tag, unchanged). When responding, the endpoint MUST send the
1079 // INIT ACK back to the same address that the original INIT (sent by this
1080 // endpoint) was sent."
1081 RTC_DLOG(LS_VERBOSE) << log_prefix()
1082 << "Received Init indicating simultaneous connections";
1083 } else {
1084 RTC_DCHECK(tcb_ != nullptr);
1085 // https://tools.ietf.org/html/rfc4960#section-5.2.2
1086 // "The outbound SCTP packet containing this INIT ACK MUST carry a
1087 // Verification Tag value equal to the Initiate Tag found in the
1088 // unexpected INIT. And the INIT ACK MUST contain a new Initiate Tag
1089 // (randomly generated; see Section 5.3.1). Other parameters for the
1090 // endpoint SHOULD be copied from the existing parameters of the
1091 // association (e.g., number of outbound streams) into the INIT ACK and
1092 // cookie."
1093 RTC_DLOG(LS_VERBOSE) << log_prefix()
1094 << "Received Init indicating restarted connection";
1095 // Create a new verification tag - different from the previous one.
1096 for (int tries = 0; tries < 10; ++tries) {
1097 connect_params_.verification_tag = VerificationTag(
1098 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
1099 if (connect_params_.verification_tag != tcb_->my_verification_tag()) {
1100 break;
1101 }
1102 }
1103
1104 // Make the initial TSN make a large jump, so that there is no overlap
1105 // with the old and new association.
1106 connect_params_.initial_tsn =
1107 TSN(*tcb_->retransmission_queue().next_tsn() + 1000000);
1108 tie_tag = tcb_->tie_tag();
1109 }
1110
1111 RTC_DLOG(LS_VERBOSE)
1112 << log_prefix()
1113 << rtc::StringFormat(
1114 "Proceeding with connection. my_verification_tag=%08x, "
1115 "my_initial_tsn=%u, peer_verification_tag=%08x, "
1116 "peer_initial_tsn=%u",
1117 *connect_params_.verification_tag, *connect_params_.initial_tsn,
1118 *chunk->initiate_tag(), *chunk->initial_tsn());
1119
1120 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1121
1122 SctpPacket::Builder b(chunk->initiate_tag(), options_);
1123 Parameters::Builder params_builder =
1124 Parameters::Builder().Add(StateCookieParameter(
1125 StateCookie(chunk->initiate_tag(), chunk->initial_tsn(),
1126 chunk->a_rwnd(), tie_tag, capabilities)
1127 .Serialize()));
1128 AddCapabilityParameters(options_, params_builder);
1129
1130 InitAckChunk init_ack(/*initiate_tag=*/connect_params_.verification_tag,
1131 options_.max_receiver_window_buffer_size,
1132 options_.announced_maximum_outgoing_streams,
1133 options_.announced_maximum_incoming_streams,
1134 connect_params_.initial_tsn, params_builder.Build());
1135 b.Add(init_ack);
Victor Boivieabf61882021-08-12 15:57:49 +02001136 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001137}
1138
Victor Boivieb6580cc2021-04-08 09:56:59 +02001139void DcSctpSocket::HandleInitAck(
1140 const CommonHeader& header,
1141 const SctpPacket::ChunkDescriptor& descriptor) {
1142 absl::optional<InitAckChunk> chunk = InitAckChunk::Parse(descriptor.data);
1143 if (!ValidateParseSuccess(chunk)) {
1144 return;
1145 }
1146
1147 if (state_ != State::kCookieWait) {
1148 // https://tools.ietf.org/html/rfc4960#section-5.2.3
1149 // "If an INIT ACK is received by an endpoint in any state other than
1150 // the COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk."
1151 RTC_DLOG(LS_VERBOSE) << log_prefix()
1152 << "Received INIT_ACK in unexpected state";
1153 return;
1154 }
1155
1156 auto cookie = chunk->parameters().get<StateCookieParameter>();
1157 if (!cookie.has_value()) {
Victor Boivieabf61882021-08-12 15:57:49 +02001158 packet_sender_.Send(
1159 SctpPacket::Builder(connect_params_.verification_tag, options_)
1160 .Add(AbortChunk(
1161 /*filled_in_verification_tag=*/false,
1162 Parameters::Builder()
1163 .Add(ProtocolViolationCause("INIT-ACK malformed"))
1164 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001165 InternalClose(ErrorKind::kProtocolViolation,
1166 "InitAck chunk doesn't contain a cookie");
1167 return;
1168 }
1169 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1170 t1_init_->Stop();
1171
Victor Boivief4fa1662021-09-24 23:01:21 +02001172 peer_implementation_ = DeterminePeerImplementation(cookie->data());
1173
Victor Boivieb6580cc2021-04-08 09:56:59 +02001174 tcb_ = std::make_unique<TransmissionControlBlock>(
1175 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
1176 send_queue_, connect_params_.verification_tag,
1177 connect_params_.initial_tsn, chunk->initiate_tag(), chunk->initial_tsn(),
Victor Boivieabf61882021-08-12 15:57:49 +02001178 chunk->a_rwnd(), MakeTieTag(callbacks_), packet_sender_,
1179 [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001180 RTC_DLOG(LS_VERBOSE) << log_prefix()
1181 << "Created peer TCB: " << tcb_->ToString();
1182
1183 SetState(State::kCookieEchoed, "INIT_ACK received");
1184
1185 // The connection isn't fully established just yet.
Victor Boiviec20f1562021-06-16 12:52:42 +02001186 tcb_->SetCookieEchoChunk(CookieEchoChunk(cookie->data()));
1187 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001188 t1_cookie_->Start();
1189}
1190
1191void DcSctpSocket::HandleCookieEcho(
1192 const CommonHeader& header,
1193 const SctpPacket::ChunkDescriptor& descriptor) {
1194 absl::optional<CookieEchoChunk> chunk =
1195 CookieEchoChunk::Parse(descriptor.data);
1196 if (!ValidateParseSuccess(chunk)) {
1197 return;
1198 }
1199
1200 absl::optional<StateCookie> cookie =
1201 StateCookie::Deserialize(chunk->cookie());
1202 if (!cookie.has_value()) {
1203 callbacks_.OnError(ErrorKind::kParseFailed, "Failed to parse state cookie");
1204 return;
1205 }
1206
1207 if (tcb_ != nullptr) {
1208 if (!HandleCookieEchoWithTCB(header, *cookie)) {
1209 return;
1210 }
1211 } else {
1212 if (header.verification_tag != connect_params_.verification_tag) {
1213 callbacks_.OnError(
1214 ErrorKind::kParseFailed,
1215 rtc::StringFormat(
1216 "Received CookieEcho with invalid verification tag: %08x, "
1217 "expected %08x",
1218 *header.verification_tag, *connect_params_.verification_tag));
1219 return;
1220 }
1221 }
1222
1223 // The init timer can be running on simultaneous connections.
1224 t1_init_->Stop();
1225 t1_cookie_->Stop();
1226 if (state_ != State::kEstablished) {
Victor Boiviec20f1562021-06-16 12:52:42 +02001227 if (tcb_ != nullptr) {
1228 tcb_->ClearCookieEchoChunk();
1229 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001230 SetState(State::kEstablished, "COOKIE_ECHO received");
1231 callbacks_.OnConnected();
1232 }
1233
1234 if (tcb_ == nullptr) {
1235 tcb_ = std::make_unique<TransmissionControlBlock>(
1236 timer_manager_, log_prefix_, options_, cookie->capabilities(),
1237 callbacks_, send_queue_, connect_params_.verification_tag,
1238 connect_params_.initial_tsn, cookie->initiate_tag(),
1239 cookie->initial_tsn(), cookie->a_rwnd(), MakeTieTag(callbacks_),
Victor Boivieabf61882021-08-12 15:57:49 +02001240 packet_sender_, [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001241 RTC_DLOG(LS_VERBOSE) << log_prefix()
1242 << "Created peer TCB: " << tcb_->ToString();
1243 }
1244
1245 SctpPacket::Builder b = tcb_->PacketBuilder();
1246 b.Add(CookieAckChunk());
1247
1248 // https://tools.ietf.org/html/rfc4960#section-5.1
1249 // "A COOKIE ACK chunk may be bundled with any pending DATA chunks (and/or
1250 // SACK chunks), but the COOKIE ACK chunk MUST be the first chunk in the
1251 // packet."
Victor Boivied3b186e2021-05-05 16:22:29 +02001252 tcb_->SendBufferedPackets(b, callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001253}
1254
1255bool DcSctpSocket::HandleCookieEchoWithTCB(const CommonHeader& header,
1256 const StateCookie& cookie) {
1257 RTC_DLOG(LS_VERBOSE) << log_prefix()
1258 << "Handling CookieEchoChunk with TCB. local_tag="
1259 << *tcb_->my_verification_tag()
1260 << ", peer_tag=" << *header.verification_tag
1261 << ", tcb_tag=" << *tcb_->peer_verification_tag()
1262 << ", cookie_tag=" << *cookie.initiate_tag()
1263 << ", local_tie_tag=" << *tcb_->tie_tag()
1264 << ", peer_tie_tag=" << *cookie.tie_tag();
1265 // https://tools.ietf.org/html/rfc4960#section-5.2.4
1266 // "Handle a COOKIE ECHO when a TCB Exists"
1267 if (header.verification_tag != tcb_->my_verification_tag() &&
1268 tcb_->peer_verification_tag() != cookie.initiate_tag() &&
1269 cookie.tie_tag() == tcb_->tie_tag()) {
1270 // "A) In this case, the peer may have restarted."
1271 if (state_ == State::kShutdownAckSent) {
1272 // "If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
1273 // that the peer has restarted ... it MUST NOT set up a new association
1274 // but instead resend the SHUTDOWN ACK and send an ERROR chunk with a
1275 // "Cookie Received While Shutting Down" error cause to its peer."
1276 SctpPacket::Builder b(cookie.initiate_tag(), options_);
1277 b.Add(ShutdownAckChunk());
1278 b.Add(ErrorChunk(Parameters::Builder()
1279 .Add(CookieReceivedWhileShuttingDownCause())
1280 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001281 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001282 callbacks_.OnError(ErrorKind::kWrongSequence,
1283 "Received COOKIE-ECHO while shutting down");
1284 return false;
1285 }
1286
1287 RTC_DLOG(LS_VERBOSE) << log_prefix()
1288 << "Received COOKIE-ECHO indicating a restarted peer";
1289
1290 // If a message was partly sent, and the peer restarted, resend it in
1291 // full by resetting the send queue.
1292 send_queue_.Reset();
1293 tcb_ = nullptr;
1294 callbacks_.OnConnectionRestarted();
1295 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1296 tcb_->peer_verification_tag() != cookie.initiate_tag()) {
1297 // TODO(boivie): Handle the peer_tag == 0?
1298 // "B) In this case, both sides may be attempting to start an
1299 // association at about the same time, but the peer endpoint started its
1300 // INIT after responding to the local endpoint's INIT."
1301 RTC_DLOG(LS_VERBOSE)
1302 << log_prefix()
1303 << "Received COOKIE-ECHO indicating simultaneous connections";
1304 tcb_ = nullptr;
1305 } else if (header.verification_tag != tcb_->my_verification_tag() &&
1306 tcb_->peer_verification_tag() == cookie.initiate_tag() &&
1307 cookie.tie_tag() == TieTag(0)) {
1308 // "C) In this case, the local endpoint's cookie has arrived late.
1309 // Before it arrived, the local endpoint sent an INIT and received an
1310 // INIT ACK and finally sent a COOKIE ECHO with the peer's same tag but
1311 // a new tag of its own. The cookie should be silently discarded. The
1312 // endpoint SHOULD NOT change states and should leave any timers
1313 // running."
1314 RTC_DLOG(LS_VERBOSE)
1315 << log_prefix()
1316 << "Received COOKIE-ECHO indicating a late COOKIE-ECHO. Discarding";
1317 return false;
1318 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1319 tcb_->peer_verification_tag() == cookie.initiate_tag()) {
1320 // "D) When both local and remote tags match, the endpoint should enter
1321 // the ESTABLISHED state, if it is in the COOKIE-ECHOED state. It
1322 // should stop any cookie timer that may be running and send a COOKIE
1323 // ACK."
1324 RTC_DLOG(LS_VERBOSE)
1325 << log_prefix()
1326 << "Received duplicate COOKIE-ECHO, probably because of peer not "
1327 "receiving COOKIE-ACK and retransmitting COOKIE-ECHO. Continuing.";
1328 }
1329 return true;
1330}
1331
1332void DcSctpSocket::HandleCookieAck(
1333 const CommonHeader& header,
1334 const SctpPacket::ChunkDescriptor& descriptor) {
1335 absl::optional<CookieAckChunk> chunk = CookieAckChunk::Parse(descriptor.data);
1336 if (!ValidateParseSuccess(chunk)) {
1337 return;
1338 }
1339
1340 if (state_ != State::kCookieEchoed) {
1341 // https://tools.ietf.org/html/rfc4960#section-5.2.5
1342 // "At any state other than COOKIE-ECHOED, an endpoint should silently
1343 // discard a received COOKIE ACK chunk."
1344 RTC_DLOG(LS_VERBOSE) << log_prefix()
1345 << "Received COOKIE_ACK not in COOKIE_ECHOED state";
1346 return;
1347 }
1348
1349 // RFC 4960, Errata ID: 4400
1350 t1_cookie_->Stop();
Victor Boiviec20f1562021-06-16 12:52:42 +02001351 tcb_->ClearCookieEchoChunk();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001352 SetState(State::kEstablished, "COOKIE_ACK received");
Victor Boivied3b186e2021-05-05 16:22:29 +02001353 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001354 callbacks_.OnConnected();
1355}
1356
1357void DcSctpSocket::DeliverReassembledMessages() {
1358 if (tcb_->reassembly_queue().HasMessages()) {
1359 for (auto& message : tcb_->reassembly_queue().FlushMessages()) {
Victor Boivied4716ea2021-08-09 12:26:32 +02001360 ++metrics_.rx_messages_count;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001361 callbacks_.OnMessageReceived(std::move(message));
1362 }
1363 }
1364}
1365
1366void DcSctpSocket::HandleSack(const CommonHeader& header,
1367 const SctpPacket::ChunkDescriptor& descriptor) {
1368 absl::optional<SackChunk> chunk = SackChunk::Parse(descriptor.data);
1369
1370 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
Victor Boivied3b186e2021-05-05 16:22:29 +02001371 TimeMs now = callbacks_.TimeMillis();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001372 SackChunk sack = ChunkValidators::Clean(*std::move(chunk));
1373
Victor Boivied3b186e2021-05-05 16:22:29 +02001374 if (tcb_->retransmission_queue().HandleSack(now, sack)) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001375 MaybeSendShutdownOrAck();
1376 // Receiving an ACK will decrease outstanding bytes (maybe now below
1377 // cwnd?) or indicate packet loss that may result in sending FORWARD-TSN.
Victor Boivied3b186e2021-05-05 16:22:29 +02001378 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001379 } else {
1380 RTC_DLOG(LS_VERBOSE) << log_prefix()
1381 << "Dropping out-of-order SACK with TSN "
1382 << *sack.cumulative_tsn_ack();
1383 }
1384 }
1385}
1386
1387void DcSctpSocket::HandleHeartbeatRequest(
1388 const CommonHeader& header,
1389 const SctpPacket::ChunkDescriptor& descriptor) {
1390 absl::optional<HeartbeatRequestChunk> chunk =
1391 HeartbeatRequestChunk::Parse(descriptor.data);
1392
1393 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1394 tcb_->heartbeat_handler().HandleHeartbeatRequest(*std::move(chunk));
1395 }
1396}
1397
1398void DcSctpSocket::HandleHeartbeatAck(
1399 const CommonHeader& header,
1400 const SctpPacket::ChunkDescriptor& descriptor) {
1401 absl::optional<HeartbeatAckChunk> chunk =
1402 HeartbeatAckChunk::Parse(descriptor.data);
1403
1404 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1405 tcb_->heartbeat_handler().HandleHeartbeatAck(*std::move(chunk));
1406 }
1407}
1408
1409void DcSctpSocket::HandleAbort(const CommonHeader& header,
1410 const SctpPacket::ChunkDescriptor& descriptor) {
1411 absl::optional<AbortChunk> chunk = AbortChunk::Parse(descriptor.data);
1412 if (ValidateParseSuccess(chunk)) {
1413 std::string error_string = ErrorCausesToString(chunk->error_causes());
1414 if (tcb_ == nullptr) {
1415 // https://tools.ietf.org/html/rfc4960#section-3.3.7
1416 // "If an endpoint receives an ABORT with a format error or no TCB is
1417 // found, it MUST silently discard it."
1418 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ABORT (" << error_string
1419 << ") on a connection with no TCB. Ignoring";
1420 return;
1421 }
1422
1423 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ABORT (" << error_string
1424 << ") - closing connection.";
1425 InternalClose(ErrorKind::kPeerReported, error_string);
1426 }
1427}
1428
1429void DcSctpSocket::HandleError(const CommonHeader& header,
1430 const SctpPacket::ChunkDescriptor& descriptor) {
1431 absl::optional<ErrorChunk> chunk = ErrorChunk::Parse(descriptor.data);
1432 if (ValidateParseSuccess(chunk)) {
1433 std::string error_string = ErrorCausesToString(chunk->error_causes());
1434 if (tcb_ == nullptr) {
1435 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ERROR (" << error_string
1436 << ") on a connection with no TCB. Ignoring";
1437 return;
1438 }
1439
1440 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ERROR: " << error_string;
1441 callbacks_.OnError(ErrorKind::kPeerReported,
1442 "Peer reported error: " + error_string);
1443 }
1444}
1445
1446void DcSctpSocket::HandleReconfig(
1447 const CommonHeader& header,
1448 const SctpPacket::ChunkDescriptor& descriptor) {
1449 absl::optional<ReConfigChunk> chunk = ReConfigChunk::Parse(descriptor.data);
1450 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1451 tcb_->stream_reset_handler().HandleReConfig(*std::move(chunk));
1452 }
1453}
1454
1455void DcSctpSocket::HandleShutdown(
1456 const CommonHeader& header,
1457 const SctpPacket::ChunkDescriptor& descriptor) {
1458 if (!ValidateParseSuccess(ShutdownChunk::Parse(descriptor.data))) {
1459 return;
1460 }
1461
1462 if (state_ == State::kClosed) {
1463 return;
1464 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1465 // https://tools.ietf.org/html/rfc4960#section-9.2
1466 // "If a SHUTDOWN is received in the COOKIE-WAIT or COOKIE ECHOED state,
1467 // the SHUTDOWN chunk SHOULD be silently discarded."
1468 } else if (state_ == State::kShutdownSent) {
1469 // https://tools.ietf.org/html/rfc4960#section-9.2
1470 // "If an endpoint is in the SHUTDOWN-SENT state and receives a
1471 // SHUTDOWN chunk from its peer, the endpoint shall respond immediately
1472 // with a SHUTDOWN ACK to its peer, and move into the SHUTDOWN-ACK-SENT
1473 // state restarting its T2-shutdown timer."
1474 SendShutdownAck();
1475 SetState(State::kShutdownAckSent, "SHUTDOWN received");
Victor Boivie50a0b122021-05-06 21:07:49 +02001476 } else if (state_ == State::kShutdownAckSent) {
1477 // TODO(webrtc:12739): This condition should be removed and handled by the
1478 // next (state_ != State::kShutdownReceived).
1479 return;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001480 } else if (state_ != State::kShutdownReceived) {
1481 RTC_DLOG(LS_VERBOSE) << log_prefix()
1482 << "Received SHUTDOWN - shutting down the socket";
1483 // https://tools.ietf.org/html/rfc4960#section-9.2
1484 // "Upon reception of the SHUTDOWN, the peer endpoint shall enter the
1485 // SHUTDOWN-RECEIVED state, stop accepting new data from its SCTP user,
1486 // and verify, by checking the Cumulative TSN Ack field of the chunk, that
1487 // all its outstanding DATA chunks have been received by the SHUTDOWN
1488 // sender."
1489 SetState(State::kShutdownReceived, "SHUTDOWN received");
1490 MaybeSendShutdownOrAck();
1491 }
1492}
1493
1494void DcSctpSocket::HandleShutdownAck(
1495 const CommonHeader& header,
1496 const SctpPacket::ChunkDescriptor& descriptor) {
1497 if (!ValidateParseSuccess(ShutdownAckChunk::Parse(descriptor.data))) {
1498 return;
1499 }
1500
1501 if (state_ == State::kShutdownSent || state_ == State::kShutdownAckSent) {
1502 // https://tools.ietf.org/html/rfc4960#section-9.2
1503 // "Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall stop
1504 // the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its peer, and
1505 // remove all record of the association."
1506
1507 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives a
1508 // SHUTDOWN ACK, it shall stop the T2-shutdown timer, send a SHUTDOWN
1509 // COMPLETE chunk to its peer, and remove all record of the association."
1510
1511 SctpPacket::Builder b = tcb_->PacketBuilder();
1512 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/false));
Victor Boivieabf61882021-08-12 15:57:49 +02001513 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001514 InternalClose(ErrorKind::kNoError, "");
1515 } else {
1516 // https://tools.ietf.org/html/rfc4960#section-8.5.1
1517 // "If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state
1518 // the procedures in Section 8.4 SHOULD be followed; in other words, it
1519 // should be treated as an Out Of The Blue packet."
1520
1521 // https://tools.ietf.org/html/rfc4960#section-8.4
1522 // "If the packet contains a SHUTDOWN ACK chunk, the receiver
1523 // should respond to the sender of the OOTB packet with a SHUTDOWN
1524 // COMPLETE. When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
1525 // packet must fill in the Verification Tag field of the outbound packet
1526 // with the Verification Tag received in the SHUTDOWN ACK and set the T
1527 // bit in the Chunk Flags to indicate that the Verification Tag is
1528 // reflected."
1529
1530 SctpPacket::Builder b(header.verification_tag, options_);
1531 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/true));
Victor Boivieabf61882021-08-12 15:57:49 +02001532 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001533 }
1534}
1535
1536void DcSctpSocket::HandleShutdownComplete(
1537 const CommonHeader& header,
1538 const SctpPacket::ChunkDescriptor& descriptor) {
1539 if (!ValidateParseSuccess(ShutdownCompleteChunk::Parse(descriptor.data))) {
1540 return;
1541 }
1542
1543 if (state_ == State::kShutdownAckSent) {
1544 // https://tools.ietf.org/html/rfc4960#section-9.2
1545 // "Upon reception of the SHUTDOWN COMPLETE chunk, the endpoint will
1546 // verify that it is in the SHUTDOWN-ACK-SENT state; if it is not, the
1547 // chunk should be discarded. If the endpoint is in the SHUTDOWN-ACK-SENT
1548 // state, the endpoint should stop the T2-shutdown timer and remove all
1549 // knowledge of the association (and thus the association enters the
1550 // CLOSED state)."
1551 InternalClose(ErrorKind::kNoError, "");
1552 }
1553}
1554
1555void DcSctpSocket::HandleForwardTsn(
1556 const CommonHeader& header,
1557 const SctpPacket::ChunkDescriptor& descriptor) {
1558 absl::optional<ForwardTsnChunk> chunk =
1559 ForwardTsnChunk::Parse(descriptor.data);
1560 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1561 HandleForwardTsnCommon(*chunk);
1562 }
1563}
1564
1565void DcSctpSocket::HandleIForwardTsn(
1566 const CommonHeader& header,
1567 const SctpPacket::ChunkDescriptor& descriptor) {
1568 absl::optional<IForwardTsnChunk> chunk =
1569 IForwardTsnChunk::Parse(descriptor.data);
1570 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1571 HandleForwardTsnCommon(*chunk);
1572 }
1573}
1574
1575void DcSctpSocket::HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk) {
1576 if (!tcb_->capabilities().partial_reliability) {
1577 SctpPacket::Builder b = tcb_->PacketBuilder();
1578 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
1579 Parameters::Builder()
1580 .Add(ProtocolViolationCause(
1581 "I-FORWARD-TSN received, but not indicated "
1582 "during connection establishment"))
1583 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001584 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001585
1586 callbacks_.OnError(ErrorKind::kProtocolViolation,
1587 "Received a FORWARD_TSN without announced peer support");
1588 return;
1589 }
1590 tcb_->data_tracker().HandleForwardTsn(chunk.new_cumulative_tsn());
1591 tcb_->reassembly_queue().Handle(chunk);
1592 // A forward TSN - for ordered streams - may allow messages to be
1593 // delivered.
1594 DeliverReassembledMessages();
1595
1596 // Processing a FORWARD_TSN might result in sending a SACK.
1597 tcb_->MaybeSendSack();
1598}
1599
1600void DcSctpSocket::MaybeSendShutdownOrAck() {
1601 if (tcb_->retransmission_queue().outstanding_bytes() != 0) {
1602 return;
1603 }
1604
1605 if (state_ == State::kShutdownPending) {
1606 // https://tools.ietf.org/html/rfc4960#section-9.2
1607 // "Once all its outstanding data has been acknowledged, the endpoint
1608 // shall send a SHUTDOWN chunk to its peer including in the Cumulative TSN
1609 // Ack field the last sequential TSN it has received from the peer. It
1610 // shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT
1611 // state.""
1612
1613 SendShutdown();
1614 t2_shutdown_->set_duration(tcb_->current_rto());
1615 t2_shutdown_->Start();
1616 SetState(State::kShutdownSent, "No more outstanding data");
1617 } else if (state_ == State::kShutdownReceived) {
1618 // https://tools.ietf.org/html/rfc4960#section-9.2
1619 // "If the receiver of the SHUTDOWN has no more outstanding DATA
1620 // chunks, the SHUTDOWN receiver MUST send a SHUTDOWN ACK and start a
1621 // T2-shutdown timer of its own, entering the SHUTDOWN-ACK-SENT state. If
1622 // the timer expires, the endpoint must resend the SHUTDOWN ACK."
1623
1624 SendShutdownAck();
1625 SetState(State::kShutdownAckSent, "No more outstanding data");
1626 }
1627}
1628
1629void DcSctpSocket::SendShutdown() {
1630 SctpPacket::Builder b = tcb_->PacketBuilder();
1631 b.Add(ShutdownChunk(tcb_->data_tracker().last_cumulative_acked_tsn()));
Victor Boivieabf61882021-08-12 15:57:49 +02001632 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001633}
1634
1635void DcSctpSocket::SendShutdownAck() {
Victor Boivieabf61882021-08-12 15:57:49 +02001636 packet_sender_.Send(tcb_->PacketBuilder().Add(ShutdownAckChunk()));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001637 t2_shutdown_->set_duration(tcb_->current_rto());
1638 t2_shutdown_->Start();
1639}
1640
Sergey Sukhanov43972812021-09-17 15:32:48 +02001641HandoverReadinessStatus DcSctpSocket::GetHandoverReadiness() const {
1642 HandoverReadinessStatus status;
1643 if (state_ != State::kClosed && state_ != State::kEstablished) {
1644 status.Add(HandoverUnreadinessReason::kWrongConnectionState);
1645 }
Sergey Sukhanov72435322021-09-21 13:31:09 +02001646 status.Add(send_queue_.GetHandoverReadiness());
Sergey Sukhanov43972812021-09-17 15:32:48 +02001647 if (tcb_) {
1648 status.Add(tcb_->GetHandoverReadiness());
1649 }
1650 return status;
1651}
1652
1653absl::optional<DcSctpSocketHandoverState>
1654DcSctpSocket::GetHandoverStateAndClose() {
Victor Boivie15a0c882021-09-28 21:38:34 +02001655 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
1656
Sergey Sukhanov43972812021-09-17 15:32:48 +02001657 if (!GetHandoverReadiness().IsReady()) {
1658 return absl::nullopt;
1659 }
1660
1661 DcSctpSocketHandoverState state;
1662
1663 if (state_ == State::kClosed) {
1664 state.socket_state = DcSctpSocketHandoverState::SocketState::kClosed;
1665 } else if (state_ == State::kEstablished) {
1666 state.socket_state = DcSctpSocketHandoverState::SocketState::kConnected;
1667 tcb_->AddHandoverState(state);
Sergey Sukhanov72435322021-09-21 13:31:09 +02001668 send_queue_.AddHandoverState(state);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001669 InternalClose(ErrorKind::kNoError, "handover");
Sergey Sukhanov43972812021-09-17 15:32:48 +02001670 }
1671
1672 return std::move(state);
1673}
1674
Victor Boivieb6580cc2021-04-08 09:56:59 +02001675} // namespace dcsctp