blob: bfe248c05511d2a290c5e30fad4d33dc8e73fa5f [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 Boivieb6580cc2021-04-08 09:56:59 +0200141} // namespace
142
143DcSctpSocket::DcSctpSocket(absl::string_view log_prefix,
144 DcSctpSocketCallbacks& callbacks,
145 std::unique_ptr<PacketObserver> packet_observer,
146 const DcSctpOptions& options)
147 : log_prefix_(std::string(log_prefix) + ": "),
148 packet_observer_(std::move(packet_observer)),
149 options_(options),
150 callbacks_(callbacks),
151 timer_manager_([this]() { return callbacks_.CreateTimeout(); }),
152 t1_init_(timer_manager_.CreateTimer(
153 "t1-init",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200154 absl::bind_front(&DcSctpSocket::OnInitTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200155 TimerOptions(options.t1_init_timeout,
156 TimerBackoffAlgorithm::kExponential,
157 options.max_init_retransmits))),
158 t1_cookie_(timer_manager_.CreateTimer(
159 "t1-cookie",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200160 absl::bind_front(&DcSctpSocket::OnCookieTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200161 TimerOptions(options.t1_cookie_timeout,
162 TimerBackoffAlgorithm::kExponential,
163 options.max_init_retransmits))),
164 t2_shutdown_(timer_manager_.CreateTimer(
165 "t2-shutdown",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200166 absl::bind_front(&DcSctpSocket::OnShutdownTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200167 TimerOptions(options.t2_shutdown_timeout,
168 TimerBackoffAlgorithm::kExponential,
169 options.max_retransmissions))),
Victor Boivieabf61882021-08-12 15:57:49 +0200170 packet_sender_(callbacks_,
171 absl::bind_front(&DcSctpSocket::OnSentPacket, this)),
Victor Boiviebd9031b2021-05-26 19:48:55 +0200172 send_queue_(
173 log_prefix_,
174 options_.max_send_buffer_size,
Victor Boivie236ac502021-05-20 19:34:18 +0200175 [this](StreamID stream_id) {
176 callbacks_.OnBufferedAmountLow(stream_id);
177 },
178 options_.total_buffered_amount_low_threshold,
179 [this]() { callbacks_.OnTotalBufferedAmountLow(); }) {}
Victor Boivieb6580cc2021-04-08 09:56:59 +0200180
181std::string DcSctpSocket::log_prefix() const {
182 return log_prefix_ + "[" + std::string(ToString(state_)) + "] ";
183}
184
185bool DcSctpSocket::IsConsistent() const {
Victor Boivie54e4e352021-09-15 10:42:26 +0200186 if (tcb_ != nullptr && tcb_->reassembly_queue().HasMessages()) {
187 return false;
188 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200189 switch (state_) {
190 case State::kClosed:
191 return (tcb_ == nullptr && !t1_init_->is_running() &&
192 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
193 case State::kCookieWait:
194 return (tcb_ == nullptr && t1_init_->is_running() &&
195 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
196 case State::kCookieEchoed:
197 return (tcb_ != nullptr && !t1_init_->is_running() &&
198 t1_cookie_->is_running() && !t2_shutdown_->is_running() &&
Victor Boiviec20f1562021-06-16 12:52:42 +0200199 tcb_->has_cookie_echo_chunk());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200200 case State::kEstablished:
201 return (tcb_ != nullptr && !t1_init_->is_running() &&
202 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
203 case State::kShutdownPending:
204 return (tcb_ != nullptr && !t1_init_->is_running() &&
205 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
206 case State::kShutdownSent:
207 return (tcb_ != nullptr && !t1_init_->is_running() &&
208 !t1_cookie_->is_running() && t2_shutdown_->is_running());
209 case State::kShutdownReceived:
210 return (tcb_ != nullptr && !t1_init_->is_running() &&
211 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
212 case State::kShutdownAckSent:
213 return (tcb_ != nullptr && !t1_init_->is_running() &&
214 !t1_cookie_->is_running() && t2_shutdown_->is_running());
215 }
216}
217
218constexpr absl::string_view DcSctpSocket::ToString(DcSctpSocket::State state) {
219 switch (state) {
220 case DcSctpSocket::State::kClosed:
221 return "CLOSED";
222 case DcSctpSocket::State::kCookieWait:
223 return "COOKIE_WAIT";
224 case DcSctpSocket::State::kCookieEchoed:
225 return "COOKIE_ECHOED";
226 case DcSctpSocket::State::kEstablished:
227 return "ESTABLISHED";
228 case DcSctpSocket::State::kShutdownPending:
229 return "SHUTDOWN_PENDING";
230 case DcSctpSocket::State::kShutdownSent:
231 return "SHUTDOWN_SENT";
232 case DcSctpSocket::State::kShutdownReceived:
233 return "SHUTDOWN_RECEIVED";
234 case DcSctpSocket::State::kShutdownAckSent:
235 return "SHUTDOWN_ACK_SENT";
236 }
237}
238
239void DcSctpSocket::SetState(State state, absl::string_view reason) {
240 if (state_ != state) {
241 RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Socket state changed from "
242 << ToString(state_) << " to " << ToString(state)
243 << " due to " << reason;
244 state_ = state;
245 }
246}
247
248void DcSctpSocket::SendInit() {
249 Parameters::Builder params_builder;
250 AddCapabilityParameters(options_, params_builder);
251 InitChunk init(/*initiate_tag=*/connect_params_.verification_tag,
252 /*a_rwnd=*/options_.max_receiver_window_buffer_size,
253 options_.announced_maximum_outgoing_streams,
254 options_.announced_maximum_incoming_streams,
255 connect_params_.initial_tsn, params_builder.Build());
256 SctpPacket::Builder b(VerificationTag(0), options_);
257 b.Add(init);
Victor Boivieabf61882021-08-12 15:57:49 +0200258 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200259}
260
261void DcSctpSocket::MakeConnectionParameters() {
262 VerificationTag new_verification_tag(
263 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
264 TSN initial_tsn(callbacks_.GetRandomInt(kMinInitialTsn, kMaxInitialTsn));
265 connect_params_.initial_tsn = initial_tsn;
266 connect_params_.verification_tag = new_verification_tag;
267}
268
269void DcSctpSocket::Connect() {
270 if (state_ == State::kClosed) {
271 MakeConnectionParameters();
272 RTC_DLOG(LS_INFO)
273 << log_prefix()
274 << rtc::StringFormat(
275 "Connecting. my_verification_tag=%08x, my_initial_tsn=%u",
276 *connect_params_.verification_tag, *connect_params_.initial_tsn);
277 SendInit();
278 t1_init_->Start();
279 SetState(State::kCookieWait, "Connect called");
280 } else {
281 RTC_DLOG(LS_WARNING) << log_prefix()
282 << "Called Connect on a socket that is not closed";
283 }
284 RTC_DCHECK(IsConsistent());
285 callbacks_.TriggerDeferred();
286}
287
Sergey Sukhanov43972812021-09-17 15:32:48 +0200288void DcSctpSocket::RestoreFromState(const DcSctpSocketHandoverState& state) {
289 if (state_ != State::kClosed) {
290 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
291 "Only closed socket can be restored from state");
292 } else {
293 if (state.socket_state ==
294 DcSctpSocketHandoverState::SocketState::kConnected) {
295 VerificationTag my_verification_tag =
296 VerificationTag(state.my_verification_tag);
297 connect_params_.verification_tag = my_verification_tag;
298
299 Capabilities capabilities;
300 capabilities.partial_reliability = state.capabilities.partial_reliability;
301 capabilities.message_interleaving =
302 state.capabilities.message_interleaving;
303 capabilities.reconfig = state.capabilities.reconfig;
304
305 tcb_ = std::make_unique<TransmissionControlBlock>(
306 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
307 send_queue_, my_verification_tag, TSN(state.my_initial_tsn),
308 VerificationTag(state.peer_verification_tag),
309 TSN(state.peer_initial_tsn), static_cast<size_t>(0),
310 TieTag(state.tie_tag), packet_sender_,
311 [this]() { return state_ == State::kEstablished; }, &state);
312 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Created peer TCB from state: "
313 << tcb_->ToString();
314
315 SetState(State::kEstablished, "restored from handover state");
316 callbacks_.OnConnected();
317 }
318 }
319
320 RTC_DCHECK(IsConsistent());
321 callbacks_.TriggerDeferred();
322}
323
Victor Boivieb6580cc2021-04-08 09:56:59 +0200324void DcSctpSocket::Shutdown() {
325 if (tcb_ != nullptr) {
326 // https://tools.ietf.org/html/rfc4960#section-9.2
327 // "Upon receipt of the SHUTDOWN primitive from its upper layer, the
328 // endpoint enters the SHUTDOWN-PENDING state and remains there until all
329 // outstanding data has been acknowledged by its peer."
Victor Boivie50a0b122021-05-06 21:07:49 +0200330
331 // TODO(webrtc:12739): Remove this check, as it just hides the problem that
332 // the socket can transition from ShutdownSent to ShutdownPending, or
333 // ShutdownAckSent to ShutdownPending which is illegal.
334 if (state_ != State::kShutdownSent && state_ != State::kShutdownAckSent) {
335 SetState(State::kShutdownPending, "Shutdown called");
336 t1_init_->Stop();
337 t1_cookie_->Stop();
338 MaybeSendShutdownOrAck();
339 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200340 } else {
341 // Connection closed before even starting to connect, or during the initial
342 // connection phase. There is no outstanding data, so the socket can just
343 // be closed (stopping any connection timers, if any), as this is the
344 // client's intention, by calling Shutdown.
345 InternalClose(ErrorKind::kNoError, "");
346 }
347 RTC_DCHECK(IsConsistent());
348 callbacks_.TriggerDeferred();
349}
350
351void DcSctpSocket::Close() {
352 if (state_ != State::kClosed) {
353 if (tcb_ != nullptr) {
354 SctpPacket::Builder b = tcb_->PacketBuilder();
355 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
356 Parameters::Builder()
357 .Add(UserInitiatedAbortCause("Close called"))
358 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +0200359 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200360 }
361 InternalClose(ErrorKind::kNoError, "");
362 } else {
363 RTC_DLOG(LS_INFO) << log_prefix() << "Called Close on a closed socket";
364 }
365 RTC_DCHECK(IsConsistent());
366 callbacks_.TriggerDeferred();
367}
368
369void DcSctpSocket::CloseConnectionBecauseOfTooManyTransmissionErrors() {
Victor Boivieabf61882021-08-12 15:57:49 +0200370 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200371 true, Parameters::Builder()
372 .Add(UserInitiatedAbortCause("Too many retransmissions"))
373 .Build())));
374 InternalClose(ErrorKind::kTooManyRetries, "Too many retransmissions");
375}
376
377void DcSctpSocket::InternalClose(ErrorKind error, absl::string_view message) {
378 if (state_ != State::kClosed) {
379 t1_init_->Stop();
380 t1_cookie_->Stop();
381 t2_shutdown_->Stop();
382 tcb_ = nullptr;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200383
384 if (error == ErrorKind::kNoError) {
385 callbacks_.OnClosed();
386 } else {
387 callbacks_.OnAborted(error, message);
388 }
389 SetState(State::kClosed, message);
390 }
391 // This method's purpose is to abort/close and make it consistent by ensuring
392 // that e.g. all timers really are stopped.
393 RTC_DCHECK(IsConsistent());
394}
395
396SendStatus DcSctpSocket::Send(DcSctpMessage message,
397 const SendOptions& send_options) {
398 if (message.payload().empty()) {
399 callbacks_.OnError(ErrorKind::kProtocolViolation,
400 "Unable to send empty message");
401 return SendStatus::kErrorMessageEmpty;
402 }
403 if (message.payload().size() > options_.max_message_size) {
404 callbacks_.OnError(ErrorKind::kProtocolViolation,
405 "Unable to send too large message");
406 return SendStatus::kErrorMessageTooLarge;
407 }
408 if (state_ == State::kShutdownPending || state_ == State::kShutdownSent ||
409 state_ == State::kShutdownReceived || state_ == State::kShutdownAckSent) {
410 // https://tools.ietf.org/html/rfc4960#section-9.2
411 // "An endpoint should reject any new data request from its upper layer
412 // if it is in the SHUTDOWN-PENDING, SHUTDOWN-SENT, SHUTDOWN-RECEIVED, or
413 // SHUTDOWN-ACK-SENT state."
414 callbacks_.OnError(ErrorKind::kWrongSequence,
415 "Unable to send message as the socket is shutting down");
416 return SendStatus::kErrorShuttingDown;
417 }
418 if (send_queue_.IsFull()) {
419 callbacks_.OnError(ErrorKind::kResourceExhaustion,
420 "Unable to send message as the send queue is full");
421 return SendStatus::kErrorResourceExhaustion;
422 }
423
Victor Boivied3b186e2021-05-05 16:22:29 +0200424 TimeMs now = callbacks_.TimeMillis();
Victor Boivied4716ea2021-08-09 12:26:32 +0200425 ++metrics_.tx_messages_count;
Victor Boivied3b186e2021-05-05 16:22:29 +0200426 send_queue_.Add(now, std::move(message), send_options);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200427 if (tcb_ != nullptr) {
Victor Boivied3b186e2021-05-05 16:22:29 +0200428 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200429 }
430
431 RTC_DCHECK(IsConsistent());
432 callbacks_.TriggerDeferred();
433 return SendStatus::kSuccess;
434}
435
436ResetStreamsStatus DcSctpSocket::ResetStreams(
437 rtc::ArrayView<const StreamID> outgoing_streams) {
438 if (tcb_ == nullptr) {
439 callbacks_.OnError(ErrorKind::kWrongSequence,
440 "Can't reset streams as the socket is not connected");
441 return ResetStreamsStatus::kNotConnected;
442 }
443 if (!tcb_->capabilities().reconfig) {
444 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
445 "Can't reset streams as the peer doesn't support it");
446 return ResetStreamsStatus::kNotSupported;
447 }
448
449 tcb_->stream_reset_handler().ResetStreams(outgoing_streams);
450 absl::optional<ReConfigChunk> reconfig =
451 tcb_->stream_reset_handler().MakeStreamResetRequest();
452 if (reconfig.has_value()) {
453 SctpPacket::Builder builder = tcb_->PacketBuilder();
454 builder.Add(*reconfig);
Victor Boivieabf61882021-08-12 15:57:49 +0200455 packet_sender_.Send(builder);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200456 }
457
458 RTC_DCHECK(IsConsistent());
459 callbacks_.TriggerDeferred();
460 return ResetStreamsStatus::kPerformed;
461}
462
463SocketState DcSctpSocket::state() const {
464 switch (state_) {
465 case State::kClosed:
466 return SocketState::kClosed;
467 case State::kCookieWait:
468 ABSL_FALLTHROUGH_INTENDED;
469 case State::kCookieEchoed:
470 return SocketState::kConnecting;
471 case State::kEstablished:
472 return SocketState::kConnected;
473 case State::kShutdownPending:
474 ABSL_FALLTHROUGH_INTENDED;
475 case State::kShutdownSent:
476 ABSL_FALLTHROUGH_INTENDED;
477 case State::kShutdownReceived:
478 ABSL_FALLTHROUGH_INTENDED;
479 case State::kShutdownAckSent:
480 return SocketState::kShuttingDown;
481 }
482}
483
Florent Castelli0810b052021-05-04 20:12:52 +0200484void DcSctpSocket::SetMaxMessageSize(size_t max_message_size) {
485 options_.max_message_size = max_message_size;
486}
487
Victor Boivie236ac502021-05-20 19:34:18 +0200488size_t DcSctpSocket::buffered_amount(StreamID stream_id) const {
489 return send_queue_.buffered_amount(stream_id);
490}
491
492size_t DcSctpSocket::buffered_amount_low_threshold(StreamID stream_id) const {
493 return send_queue_.buffered_amount_low_threshold(stream_id);
494}
495
496void DcSctpSocket::SetBufferedAmountLowThreshold(StreamID stream_id,
497 size_t bytes) {
498 send_queue_.SetBufferedAmountLowThreshold(stream_id, bytes);
499}
500
Victor Boivied4716ea2021-08-09 12:26:32 +0200501Metrics DcSctpSocket::GetMetrics() const {
502 Metrics metrics = metrics_;
503
504 if (tcb_ != nullptr) {
505 // Update the metrics with some stats that are extracted from
506 // sub-components.
507 metrics.cwnd_bytes = tcb_->cwnd();
508 metrics.srtt_ms = tcb_->current_srtt().value();
509 size_t packet_payload_size =
510 options_.mtu - SctpPacket::kHeaderSize - DataChunk::kHeaderSize;
511 metrics.unack_data_count =
512 tcb_->retransmission_queue().outstanding_items() +
513 (send_queue_.total_buffered_amount() + packet_payload_size - 1) /
514 packet_payload_size;
515 metrics.peer_rwnd_bytes = tcb_->retransmission_queue().rwnd();
516 }
517
518 return metrics;
519}
520
Victor Boivieb6580cc2021-04-08 09:56:59 +0200521void DcSctpSocket::MaybeSendShutdownOnPacketReceived(const SctpPacket& packet) {
522 if (state_ == State::kShutdownSent) {
523 bool has_data_chunk =
524 std::find_if(packet.descriptors().begin(), packet.descriptors().end(),
525 [](const SctpPacket::ChunkDescriptor& descriptor) {
526 return descriptor.type == DataChunk::kType;
527 }) != packet.descriptors().end();
528 if (has_data_chunk) {
529 // https://tools.ietf.org/html/rfc4960#section-9.2
530 // "While in the SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately
531 // respond to each received packet containing one or more DATA chunks with
532 // a SHUTDOWN chunk and restart the T2-shutdown timer.""
533 SendShutdown();
534 t2_shutdown_->set_duration(tcb_->current_rto());
535 t2_shutdown_->Start();
536 }
537 }
538}
539
540bool DcSctpSocket::ValidatePacket(const SctpPacket& packet) {
541 const CommonHeader& header = packet.common_header();
542 VerificationTag my_verification_tag =
543 tcb_ != nullptr ? tcb_->my_verification_tag() : VerificationTag(0);
544
545 if (header.verification_tag == VerificationTag(0)) {
546 if (packet.descriptors().size() == 1 &&
547 packet.descriptors()[0].type == InitChunk::kType) {
548 // https://tools.ietf.org/html/rfc4960#section-8.5.1
549 // "When an endpoint receives an SCTP packet with the Verification Tag
550 // set to 0, it should verify that the packet contains only an INIT chunk.
551 // Otherwise, the receiver MUST silently discard the packet.""
552 return true;
553 }
554 callbacks_.OnError(
555 ErrorKind::kParseFailed,
556 "Only a single INIT chunk can be present in packets sent on "
557 "verification_tag = 0");
558 return false;
559 }
560
561 if (packet.descriptors().size() == 1 &&
562 packet.descriptors()[0].type == AbortChunk::kType) {
563 // https://tools.ietf.org/html/rfc4960#section-8.5.1
564 // "The receiver of an ABORT MUST accept the packet if the Verification
565 // Tag field of the packet matches its own tag and the T bit is not set OR
566 // if it is set to its peer's tag and the T bit is set in the Chunk Flags.
567 // Otherwise, the receiver MUST silently discard the packet and take no
568 // further action."
569 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
570 if (t_bit && tcb_ == nullptr) {
571 // Can't verify the tag - assume it's okey.
572 return true;
573 }
574 if ((!t_bit && header.verification_tag == my_verification_tag) ||
575 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
576 return true;
577 }
578 callbacks_.OnError(ErrorKind::kParseFailed,
579 "ABORT chunk verification tag was wrong");
580 return false;
581 }
582
583 if (packet.descriptors()[0].type == InitAckChunk::kType) {
584 if (header.verification_tag == connect_params_.verification_tag) {
585 return true;
586 }
587 callbacks_.OnError(
588 ErrorKind::kParseFailed,
589 rtc::StringFormat(
590 "Packet has invalid verification tag: %08x, expected %08x",
591 *header.verification_tag, *connect_params_.verification_tag));
592 return false;
593 }
594
595 if (packet.descriptors()[0].type == CookieEchoChunk::kType) {
596 // Handled in chunk handler (due to RFC 4960, section 5.2.4).
597 return true;
598 }
599
600 if (packet.descriptors().size() == 1 &&
601 packet.descriptors()[0].type == ShutdownCompleteChunk::kType) {
602 // https://tools.ietf.org/html/rfc4960#section-8.5.1
603 // "The receiver of a SHUTDOWN COMPLETE shall accept the packet if the
604 // Verification Tag field of the packet matches its own tag and the T bit is
605 // not set OR if it is set to its peer's tag and the T bit is set in the
606 // Chunk Flags. Otherwise, the receiver MUST silently discard the packet
607 // and take no further action."
608 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
609 if (t_bit && tcb_ == nullptr) {
610 // Can't verify the tag - assume it's okey.
611 return true;
612 }
613 if ((!t_bit && header.verification_tag == my_verification_tag) ||
614 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
615 return true;
616 }
617 callbacks_.OnError(ErrorKind::kParseFailed,
618 "SHUTDOWN_COMPLETE chunk verification tag was wrong");
619 return false;
620 }
621
622 // https://tools.ietf.org/html/rfc4960#section-8.5
623 // "When receiving an SCTP packet, the endpoint MUST ensure that the value
624 // in the Verification Tag field of the received SCTP packet matches its own
625 // tag. If the received Verification Tag value does not match the receiver's
626 // own tag value, the receiver shall silently discard the packet and shall not
627 // process it any further..."
628 if (header.verification_tag == my_verification_tag) {
629 return true;
630 }
631
632 callbacks_.OnError(
633 ErrorKind::kParseFailed,
634 rtc::StringFormat(
635 "Packet has invalid verification tag: %08x, expected %08x",
636 *header.verification_tag, *my_verification_tag));
637 return false;
638}
639
640void DcSctpSocket::HandleTimeout(TimeoutID timeout_id) {
641 timer_manager_.HandleTimeout(timeout_id);
642
643 if (tcb_ != nullptr && tcb_->HasTooManyTxErrors()) {
644 // Tearing down the TCB has to be done outside the handlers.
645 CloseConnectionBecauseOfTooManyTransmissionErrors();
646 }
647
648 RTC_DCHECK(IsConsistent());
649 callbacks_.TriggerDeferred();
650}
651
652void DcSctpSocket::ReceivePacket(rtc::ArrayView<const uint8_t> data) {
Victor Boivied4716ea2021-08-09 12:26:32 +0200653 ++metrics_.rx_packets_count;
654
Victor Boivieb6580cc2021-04-08 09:56:59 +0200655 if (packet_observer_ != nullptr) {
656 packet_observer_->OnReceivedPacket(callbacks_.TimeMillis(), data);
657 }
658
659 absl::optional<SctpPacket> packet =
660 SctpPacket::Parse(data, options_.disable_checksum_verification);
661 if (!packet.has_value()) {
662 // https://tools.ietf.org/html/rfc4960#section-6.8
663 // "The default procedure for handling invalid SCTP packets is to
664 // silently discard them."
665 callbacks_.OnError(ErrorKind::kParseFailed,
666 "Failed to parse received SCTP packet");
667 RTC_DCHECK(IsConsistent());
668 callbacks_.TriggerDeferred();
669 return;
670 }
671
672 if (RTC_DLOG_IS_ON) {
673 for (const auto& descriptor : packet->descriptors()) {
674 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received "
675 << DebugConvertChunkToString(descriptor.data);
676 }
677 }
678
679 if (!ValidatePacket(*packet)) {
680 RTC_DLOG(LS_VERBOSE) << log_prefix()
681 << "Packet failed verification tag check - dropping";
682 RTC_DCHECK(IsConsistent());
683 callbacks_.TriggerDeferred();
684 return;
685 }
686
687 MaybeSendShutdownOnPacketReceived(*packet);
688
689 for (const auto& descriptor : packet->descriptors()) {
690 if (!Dispatch(packet->common_header(), descriptor)) {
691 break;
692 }
693 }
694
695 if (tcb_ != nullptr) {
696 tcb_->data_tracker().ObservePacketEnd();
697 tcb_->MaybeSendSack();
698 }
699
700 RTC_DCHECK(IsConsistent());
701 callbacks_.TriggerDeferred();
702}
703
704void DcSctpSocket::DebugPrintOutgoing(rtc::ArrayView<const uint8_t> payload) {
705 auto packet = SctpPacket::Parse(payload);
706 RTC_DCHECK(packet.has_value());
707
708 for (const auto& desc : packet->descriptors()) {
709 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Sent "
710 << DebugConvertChunkToString(desc.data);
711 }
712}
713
714bool DcSctpSocket::Dispatch(const CommonHeader& header,
715 const SctpPacket::ChunkDescriptor& descriptor) {
716 switch (descriptor.type) {
717 case DataChunk::kType:
718 HandleData(header, descriptor);
719 break;
720 case InitChunk::kType:
721 HandleInit(header, descriptor);
722 break;
723 case InitAckChunk::kType:
724 HandleInitAck(header, descriptor);
725 break;
726 case SackChunk::kType:
727 HandleSack(header, descriptor);
728 break;
729 case HeartbeatRequestChunk::kType:
730 HandleHeartbeatRequest(header, descriptor);
731 break;
732 case HeartbeatAckChunk::kType:
733 HandleHeartbeatAck(header, descriptor);
734 break;
735 case AbortChunk::kType:
736 HandleAbort(header, descriptor);
737 break;
738 case ErrorChunk::kType:
739 HandleError(header, descriptor);
740 break;
741 case CookieEchoChunk::kType:
742 HandleCookieEcho(header, descriptor);
743 break;
744 case CookieAckChunk::kType:
745 HandleCookieAck(header, descriptor);
746 break;
747 case ShutdownChunk::kType:
748 HandleShutdown(header, descriptor);
749 break;
750 case ShutdownAckChunk::kType:
751 HandleShutdownAck(header, descriptor);
752 break;
753 case ShutdownCompleteChunk::kType:
754 HandleShutdownComplete(header, descriptor);
755 break;
756 case ReConfigChunk::kType:
757 HandleReconfig(header, descriptor);
758 break;
759 case ForwardTsnChunk::kType:
760 HandleForwardTsn(header, descriptor);
761 break;
762 case IDataChunk::kType:
763 HandleIData(header, descriptor);
764 break;
765 case IForwardTsnChunk::kType:
766 HandleForwardTsn(header, descriptor);
767 break;
768 default:
769 return HandleUnrecognizedChunk(descriptor);
770 }
771 return true;
772}
773
774bool DcSctpSocket::HandleUnrecognizedChunk(
775 const SctpPacket::ChunkDescriptor& descriptor) {
776 bool report_as_error = (descriptor.type & 0x40) != 0;
777 bool continue_processing = (descriptor.type & 0x80) != 0;
778 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received unknown chunk: "
779 << static_cast<int>(descriptor.type);
780 if (report_as_error) {
781 rtc::StringBuilder sb;
782 sb << "Received unknown chunk of type: "
783 << static_cast<int>(descriptor.type) << " with report-error bit set";
784 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
785 RTC_DLOG(LS_VERBOSE)
786 << log_prefix()
787 << "Unknown chunk, with type indicating it should be reported.";
788
789 // https://tools.ietf.org/html/rfc4960#section-3.2
790 // "... report in an ERROR chunk using the 'Unrecognized Chunk Type'
791 // cause."
792 if (tcb_ != nullptr) {
793 // Need TCB - this chunk must be sent with a correct verification tag.
Victor Boivieabf61882021-08-12 15:57:49 +0200794 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200795 ErrorChunk(Parameters::Builder()
796 .Add(UnrecognizedChunkTypeCause(std::vector<uint8_t>(
797 descriptor.data.begin(), descriptor.data.end())))
798 .Build())));
799 }
800 }
801 if (!continue_processing) {
802 // https://tools.ietf.org/html/rfc4960#section-3.2
803 // "Stop processing this SCTP packet and discard it, do not process any
804 // further chunks within it."
805 RTC_DLOG(LS_VERBOSE) << log_prefix()
806 << "Unknown chunk, with type indicating not to "
807 "process any further chunks";
808 }
809
810 return continue_processing;
811}
812
813absl::optional<DurationMs> DcSctpSocket::OnInitTimerExpiry() {
814 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_init_->name()
815 << " has expired: " << t1_init_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200816 << "/" << t1_init_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200817 RTC_DCHECK(state_ == State::kCookieWait);
818
819 if (t1_init_->is_running()) {
820 SendInit();
821 } else {
822 InternalClose(ErrorKind::kTooManyRetries, "No INIT_ACK received");
823 }
824 RTC_DCHECK(IsConsistent());
825 return absl::nullopt;
826}
827
828absl::optional<DurationMs> DcSctpSocket::OnCookieTimerExpiry() {
829 // https://tools.ietf.org/html/rfc4960#section-4
830 // "If the T1-cookie timer expires, the endpoint MUST retransmit COOKIE
831 // ECHO and restart the T1-cookie timer without changing state. This MUST
832 // be repeated up to 'Max.Init.Retransmits' times. After that, the endpoint
833 // MUST abort the initialization process and report the error to the SCTP
834 // user."
835 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_cookie_->name()
836 << " has expired: " << t1_cookie_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200837 << "/"
838 << t1_cookie_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200839
840 RTC_DCHECK(state_ == State::kCookieEchoed);
841
842 if (t1_cookie_->is_running()) {
Victor Boiviec20f1562021-06-16 12:52:42 +0200843 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200844 } else {
845 InternalClose(ErrorKind::kTooManyRetries, "No COOKIE_ACK received");
846 }
847
848 RTC_DCHECK(IsConsistent());
849 return absl::nullopt;
850}
851
852absl::optional<DurationMs> DcSctpSocket::OnShutdownTimerExpiry() {
853 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t2_shutdown_->name()
854 << " has expired: " << t2_shutdown_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200855 << "/"
856 << t2_shutdown_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200857
Victor Boivie914925f2021-05-07 11:22:50 +0200858 if (!t2_shutdown_->is_running()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +0200859 // https://tools.ietf.org/html/rfc4960#section-9.2
860 // "An endpoint should limit the number of retransmissions of the SHUTDOWN
861 // chunk to the protocol parameter 'Association.Max.Retrans'. If this
862 // threshold is exceeded, the endpoint should destroy the TCB..."
863
Victor Boivieabf61882021-08-12 15:57:49 +0200864 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200865 AbortChunk(true, Parameters::Builder()
866 .Add(UserInitiatedAbortCause(
867 "Too many retransmissions of SHUTDOWN"))
868 .Build())));
869
870 InternalClose(ErrorKind::kTooManyRetries, "No SHUTDOWN_ACK received");
Victor Boivie914925f2021-05-07 11:22:50 +0200871 RTC_DCHECK(IsConsistent());
872 return absl::nullopt;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200873 }
Victor Boivie914925f2021-05-07 11:22:50 +0200874
875 // https://tools.ietf.org/html/rfc4960#section-9.2
876 // "If the timer expires, the endpoint must resend the SHUTDOWN with the
877 // updated last sequential TSN received from its peer."
878 SendShutdown();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200879 RTC_DCHECK(IsConsistent());
880 return tcb_->current_rto();
881}
882
Victor Boivieabf61882021-08-12 15:57:49 +0200883void DcSctpSocket::OnSentPacket(rtc::ArrayView<const uint8_t> packet,
884 SendPacketStatus status) {
885 // The packet observer is invoked even if the packet was failed to be sent, to
886 // indicate an attempt was made.
Victor Boivieb6580cc2021-04-08 09:56:59 +0200887 if (packet_observer_ != nullptr) {
Victor Boivieabf61882021-08-12 15:57:49 +0200888 packet_observer_->OnSentPacket(callbacks_.TimeMillis(), packet);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200889 }
Victor Boivieabf61882021-08-12 15:57:49 +0200890
891 if (status == SendPacketStatus::kSuccess) {
892 if (RTC_DLOG_IS_ON) {
893 DebugPrintOutgoing(packet);
894 }
895
896 // The heartbeat interval timer is restarted for every sent packet, to
897 // fire when the outgoing channel is inactive.
898 if (tcb_ != nullptr) {
899 tcb_->heartbeat_handler().RestartTimer();
900 }
901
902 ++metrics_.tx_packets_count;
903 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200904}
905
906bool DcSctpSocket::ValidateHasTCB() {
907 if (tcb_ != nullptr) {
908 return true;
909 }
910
911 callbacks_.OnError(
912 ErrorKind::kNotConnected,
913 "Received unexpected commands on socket that is not connected");
914 return false;
915}
916
917void DcSctpSocket::ReportFailedToParseChunk(int chunk_type) {
918 rtc::StringBuilder sb;
919 sb << "Failed to parse chunk of type: " << chunk_type;
920 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
921}
922
923void DcSctpSocket::HandleData(const CommonHeader& header,
924 const SctpPacket::ChunkDescriptor& descriptor) {
925 absl::optional<DataChunk> chunk = DataChunk::Parse(descriptor.data);
926 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
927 HandleDataCommon(*chunk);
928 }
929}
930
931void DcSctpSocket::HandleIData(const CommonHeader& header,
932 const SctpPacket::ChunkDescriptor& descriptor) {
933 absl::optional<IDataChunk> chunk = IDataChunk::Parse(descriptor.data);
934 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
935 HandleDataCommon(*chunk);
936 }
937}
938
939void DcSctpSocket::HandleDataCommon(AnyDataChunk& chunk) {
940 TSN tsn = chunk.tsn();
941 AnyDataChunk::ImmediateAckFlag immediate_ack = chunk.options().immediate_ack;
942 Data data = std::move(chunk).extract();
943
944 if (data.payload.empty()) {
945 // Empty DATA chunks are illegal.
Victor Boivieabf61882021-08-12 15:57:49 +0200946 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200947 ErrorChunk(Parameters::Builder().Add(NoUserDataCause(tsn)).Build())));
948 callbacks_.OnError(ErrorKind::kProtocolViolation,
949 "Received DATA chunk with no user data");
950 return;
951 }
952
953 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Handle DATA, queue_size="
954 << tcb_->reassembly_queue().queued_bytes()
955 << ", water_mark="
956 << tcb_->reassembly_queue().watermark_bytes()
957 << ", full=" << tcb_->reassembly_queue().is_full()
958 << ", above="
959 << tcb_->reassembly_queue().is_above_watermark();
960
961 if (tcb_->reassembly_queue().is_full()) {
962 // If the reassembly queue is full, there is nothing that can be done. The
963 // specification only allows dropping gap-ack-blocks, and that's not
964 // likely to help as the socket has been trying to fill gaps since the
965 // watermark was reached.
Victor Boivieabf61882021-08-12 15:57:49 +0200966 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200967 true, Parameters::Builder().Add(OutOfResourceErrorCause()).Build())));
968 InternalClose(ErrorKind::kResourceExhaustion,
969 "Reassembly Queue is exhausted");
970 return;
971 }
972
973 if (tcb_->reassembly_queue().is_above_watermark()) {
974 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Is above high watermark";
975 // If the reassembly queue is above its high watermark, only accept data
976 // chunks that increase its cumulative ack tsn in an attempt to fill gaps
977 // to deliver messages.
978 if (!tcb_->data_tracker().will_increase_cum_ack_tsn(tsn)) {
979 RTC_DLOG(LS_VERBOSE) << log_prefix()
980 << "Rejected data because of exceeding watermark";
981 tcb_->data_tracker().ForceImmediateSack();
982 return;
983 }
984 }
985
986 if (!tcb_->data_tracker().IsTSNValid(tsn)) {
987 RTC_DLOG(LS_VERBOSE) << log_prefix()
988 << "Rejected data because of failing TSN validity";
989 return;
990 }
991
992 tcb_->data_tracker().Observe(tsn, immediate_ack);
993 tcb_->reassembly_queue().MaybeResetStreamsDeferred(
994 tcb_->data_tracker().last_cumulative_acked_tsn());
995 tcb_->reassembly_queue().Add(tsn, std::move(data));
996 DeliverReassembledMessages();
997}
998
999void DcSctpSocket::HandleInit(const CommonHeader& header,
1000 const SctpPacket::ChunkDescriptor& descriptor) {
1001 absl::optional<InitChunk> chunk = InitChunk::Parse(descriptor.data);
1002 if (!ValidateParseSuccess(chunk)) {
1003 return;
1004 }
1005
1006 if (chunk->initiate_tag() == VerificationTag(0) ||
1007 chunk->nbr_outbound_streams() == 0 || chunk->nbr_inbound_streams() == 0) {
1008 // https://tools.ietf.org/html/rfc4960#section-3.3.2
1009 // "If the value of the Initiate Tag in a received INIT chunk is found
1010 // to be 0, the receiver MUST treat it as an error and close the
1011 // association by transmitting an ABORT."
1012
1013 // "A receiver of an INIT with the OS value set to 0 SHOULD abort the
1014 // association."
1015
1016 // "A receiver of an INIT with the MIS value of 0 SHOULD abort the
1017 // association."
1018
Victor Boivieabf61882021-08-12 15:57:49 +02001019 packet_sender_.Send(
1020 SctpPacket::Builder(VerificationTag(0), options_)
1021 .Add(AbortChunk(
1022 /*filled_in_verification_tag=*/false,
1023 Parameters::Builder()
1024 .Add(ProtocolViolationCause("INIT malformed"))
1025 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001026 InternalClose(ErrorKind::kProtocolViolation, "Received invalid INIT");
1027 return;
1028 }
1029
1030 if (state_ == State::kShutdownAckSent) {
1031 // https://tools.ietf.org/html/rfc4960#section-9.2
1032 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives an
1033 // INIT chunk (e.g., if the SHUTDOWN COMPLETE was lost) with source and
1034 // destination transport addresses (either in the IP addresses or in the
1035 // INIT chunk) that belong to this association, it should discard the INIT
1036 // chunk and retransmit the SHUTDOWN ACK chunk."
1037 RTC_DLOG(LS_VERBOSE) << log_prefix()
1038 << "Received Init indicating lost ShutdownComplete";
1039 SendShutdownAck();
1040 return;
1041 }
1042
1043 TieTag tie_tag(0);
1044 if (state_ == State::kClosed) {
1045 RTC_DLOG(LS_VERBOSE) << log_prefix()
1046 << "Received Init in closed state (normal)";
1047
1048 MakeConnectionParameters();
1049 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1050 // https://tools.ietf.org/html/rfc4960#section-5.2.1
1051 // "This usually indicates an initialization collision, i.e., each
1052 // endpoint is attempting, at about the same time, to establish an
1053 // association with the other endpoint. Upon receipt of an INIT in the
1054 // COOKIE-WAIT state, an endpoint MUST respond with an INIT ACK using the
1055 // same parameters it sent in its original INIT chunk (including its
1056 // Initiate Tag, unchanged). When responding, the endpoint MUST send the
1057 // INIT ACK back to the same address that the original INIT (sent by this
1058 // endpoint) was sent."
1059 RTC_DLOG(LS_VERBOSE) << log_prefix()
1060 << "Received Init indicating simultaneous connections";
1061 } else {
1062 RTC_DCHECK(tcb_ != nullptr);
1063 // https://tools.ietf.org/html/rfc4960#section-5.2.2
1064 // "The outbound SCTP packet containing this INIT ACK MUST carry a
1065 // Verification Tag value equal to the Initiate Tag found in the
1066 // unexpected INIT. And the INIT ACK MUST contain a new Initiate Tag
1067 // (randomly generated; see Section 5.3.1). Other parameters for the
1068 // endpoint SHOULD be copied from the existing parameters of the
1069 // association (e.g., number of outbound streams) into the INIT ACK and
1070 // cookie."
1071 RTC_DLOG(LS_VERBOSE) << log_prefix()
1072 << "Received Init indicating restarted connection";
1073 // Create a new verification tag - different from the previous one.
1074 for (int tries = 0; tries < 10; ++tries) {
1075 connect_params_.verification_tag = VerificationTag(
1076 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
1077 if (connect_params_.verification_tag != tcb_->my_verification_tag()) {
1078 break;
1079 }
1080 }
1081
1082 // Make the initial TSN make a large jump, so that there is no overlap
1083 // with the old and new association.
1084 connect_params_.initial_tsn =
1085 TSN(*tcb_->retransmission_queue().next_tsn() + 1000000);
1086 tie_tag = tcb_->tie_tag();
1087 }
1088
1089 RTC_DLOG(LS_VERBOSE)
1090 << log_prefix()
1091 << rtc::StringFormat(
1092 "Proceeding with connection. my_verification_tag=%08x, "
1093 "my_initial_tsn=%u, peer_verification_tag=%08x, "
1094 "peer_initial_tsn=%u",
1095 *connect_params_.verification_tag, *connect_params_.initial_tsn,
1096 *chunk->initiate_tag(), *chunk->initial_tsn());
1097
1098 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1099
1100 SctpPacket::Builder b(chunk->initiate_tag(), options_);
1101 Parameters::Builder params_builder =
1102 Parameters::Builder().Add(StateCookieParameter(
1103 StateCookie(chunk->initiate_tag(), chunk->initial_tsn(),
1104 chunk->a_rwnd(), tie_tag, capabilities)
1105 .Serialize()));
1106 AddCapabilityParameters(options_, params_builder);
1107
1108 InitAckChunk init_ack(/*initiate_tag=*/connect_params_.verification_tag,
1109 options_.max_receiver_window_buffer_size,
1110 options_.announced_maximum_outgoing_streams,
1111 options_.announced_maximum_incoming_streams,
1112 connect_params_.initial_tsn, params_builder.Build());
1113 b.Add(init_ack);
Victor Boivieabf61882021-08-12 15:57:49 +02001114 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001115}
1116
Victor Boivieb6580cc2021-04-08 09:56:59 +02001117void DcSctpSocket::HandleInitAck(
1118 const CommonHeader& header,
1119 const SctpPacket::ChunkDescriptor& descriptor) {
1120 absl::optional<InitAckChunk> chunk = InitAckChunk::Parse(descriptor.data);
1121 if (!ValidateParseSuccess(chunk)) {
1122 return;
1123 }
1124
1125 if (state_ != State::kCookieWait) {
1126 // https://tools.ietf.org/html/rfc4960#section-5.2.3
1127 // "If an INIT ACK is received by an endpoint in any state other than
1128 // the COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk."
1129 RTC_DLOG(LS_VERBOSE) << log_prefix()
1130 << "Received INIT_ACK in unexpected state";
1131 return;
1132 }
1133
1134 auto cookie = chunk->parameters().get<StateCookieParameter>();
1135 if (!cookie.has_value()) {
Victor Boivieabf61882021-08-12 15:57:49 +02001136 packet_sender_.Send(
1137 SctpPacket::Builder(connect_params_.verification_tag, options_)
1138 .Add(AbortChunk(
1139 /*filled_in_verification_tag=*/false,
1140 Parameters::Builder()
1141 .Add(ProtocolViolationCause("INIT-ACK malformed"))
1142 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001143 InternalClose(ErrorKind::kProtocolViolation,
1144 "InitAck chunk doesn't contain a cookie");
1145 return;
1146 }
1147 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1148 t1_init_->Stop();
1149
1150 tcb_ = std::make_unique<TransmissionControlBlock>(
1151 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
1152 send_queue_, connect_params_.verification_tag,
1153 connect_params_.initial_tsn, chunk->initiate_tag(), chunk->initial_tsn(),
Victor Boivieabf61882021-08-12 15:57:49 +02001154 chunk->a_rwnd(), MakeTieTag(callbacks_), packet_sender_,
1155 [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001156 RTC_DLOG(LS_VERBOSE) << log_prefix()
1157 << "Created peer TCB: " << tcb_->ToString();
1158
1159 SetState(State::kCookieEchoed, "INIT_ACK received");
1160
1161 // The connection isn't fully established just yet.
Victor Boiviec20f1562021-06-16 12:52:42 +02001162 tcb_->SetCookieEchoChunk(CookieEchoChunk(cookie->data()));
1163 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001164 t1_cookie_->Start();
1165}
1166
1167void DcSctpSocket::HandleCookieEcho(
1168 const CommonHeader& header,
1169 const SctpPacket::ChunkDescriptor& descriptor) {
1170 absl::optional<CookieEchoChunk> chunk =
1171 CookieEchoChunk::Parse(descriptor.data);
1172 if (!ValidateParseSuccess(chunk)) {
1173 return;
1174 }
1175
1176 absl::optional<StateCookie> cookie =
1177 StateCookie::Deserialize(chunk->cookie());
1178 if (!cookie.has_value()) {
1179 callbacks_.OnError(ErrorKind::kParseFailed, "Failed to parse state cookie");
1180 return;
1181 }
1182
1183 if (tcb_ != nullptr) {
1184 if (!HandleCookieEchoWithTCB(header, *cookie)) {
1185 return;
1186 }
1187 } else {
1188 if (header.verification_tag != connect_params_.verification_tag) {
1189 callbacks_.OnError(
1190 ErrorKind::kParseFailed,
1191 rtc::StringFormat(
1192 "Received CookieEcho with invalid verification tag: %08x, "
1193 "expected %08x",
1194 *header.verification_tag, *connect_params_.verification_tag));
1195 return;
1196 }
1197 }
1198
1199 // The init timer can be running on simultaneous connections.
1200 t1_init_->Stop();
1201 t1_cookie_->Stop();
1202 if (state_ != State::kEstablished) {
Victor Boiviec20f1562021-06-16 12:52:42 +02001203 if (tcb_ != nullptr) {
1204 tcb_->ClearCookieEchoChunk();
1205 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001206 SetState(State::kEstablished, "COOKIE_ECHO received");
1207 callbacks_.OnConnected();
1208 }
1209
1210 if (tcb_ == nullptr) {
1211 tcb_ = std::make_unique<TransmissionControlBlock>(
1212 timer_manager_, log_prefix_, options_, cookie->capabilities(),
1213 callbacks_, send_queue_, connect_params_.verification_tag,
1214 connect_params_.initial_tsn, cookie->initiate_tag(),
1215 cookie->initial_tsn(), cookie->a_rwnd(), MakeTieTag(callbacks_),
Victor Boivieabf61882021-08-12 15:57:49 +02001216 packet_sender_, [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001217 RTC_DLOG(LS_VERBOSE) << log_prefix()
1218 << "Created peer TCB: " << tcb_->ToString();
1219 }
1220
1221 SctpPacket::Builder b = tcb_->PacketBuilder();
1222 b.Add(CookieAckChunk());
1223
1224 // https://tools.ietf.org/html/rfc4960#section-5.1
1225 // "A COOKIE ACK chunk may be bundled with any pending DATA chunks (and/or
1226 // SACK chunks), but the COOKIE ACK chunk MUST be the first chunk in the
1227 // packet."
Victor Boivied3b186e2021-05-05 16:22:29 +02001228 tcb_->SendBufferedPackets(b, callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001229}
1230
1231bool DcSctpSocket::HandleCookieEchoWithTCB(const CommonHeader& header,
1232 const StateCookie& cookie) {
1233 RTC_DLOG(LS_VERBOSE) << log_prefix()
1234 << "Handling CookieEchoChunk with TCB. local_tag="
1235 << *tcb_->my_verification_tag()
1236 << ", peer_tag=" << *header.verification_tag
1237 << ", tcb_tag=" << *tcb_->peer_verification_tag()
1238 << ", cookie_tag=" << *cookie.initiate_tag()
1239 << ", local_tie_tag=" << *tcb_->tie_tag()
1240 << ", peer_tie_tag=" << *cookie.tie_tag();
1241 // https://tools.ietf.org/html/rfc4960#section-5.2.4
1242 // "Handle a COOKIE ECHO when a TCB Exists"
1243 if (header.verification_tag != tcb_->my_verification_tag() &&
1244 tcb_->peer_verification_tag() != cookie.initiate_tag() &&
1245 cookie.tie_tag() == tcb_->tie_tag()) {
1246 // "A) In this case, the peer may have restarted."
1247 if (state_ == State::kShutdownAckSent) {
1248 // "If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
1249 // that the peer has restarted ... it MUST NOT set up a new association
1250 // but instead resend the SHUTDOWN ACK and send an ERROR chunk with a
1251 // "Cookie Received While Shutting Down" error cause to its peer."
1252 SctpPacket::Builder b(cookie.initiate_tag(), options_);
1253 b.Add(ShutdownAckChunk());
1254 b.Add(ErrorChunk(Parameters::Builder()
1255 .Add(CookieReceivedWhileShuttingDownCause())
1256 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001257 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001258 callbacks_.OnError(ErrorKind::kWrongSequence,
1259 "Received COOKIE-ECHO while shutting down");
1260 return false;
1261 }
1262
1263 RTC_DLOG(LS_VERBOSE) << log_prefix()
1264 << "Received COOKIE-ECHO indicating a restarted peer";
1265
1266 // If a message was partly sent, and the peer restarted, resend it in
1267 // full by resetting the send queue.
1268 send_queue_.Reset();
1269 tcb_ = nullptr;
1270 callbacks_.OnConnectionRestarted();
1271 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1272 tcb_->peer_verification_tag() != cookie.initiate_tag()) {
1273 // TODO(boivie): Handle the peer_tag == 0?
1274 // "B) In this case, both sides may be attempting to start an
1275 // association at about the same time, but the peer endpoint started its
1276 // INIT after responding to the local endpoint's INIT."
1277 RTC_DLOG(LS_VERBOSE)
1278 << log_prefix()
1279 << "Received COOKIE-ECHO indicating simultaneous connections";
1280 tcb_ = nullptr;
1281 } else if (header.verification_tag != tcb_->my_verification_tag() &&
1282 tcb_->peer_verification_tag() == cookie.initiate_tag() &&
1283 cookie.tie_tag() == TieTag(0)) {
1284 // "C) In this case, the local endpoint's cookie has arrived late.
1285 // Before it arrived, the local endpoint sent an INIT and received an
1286 // INIT ACK and finally sent a COOKIE ECHO with the peer's same tag but
1287 // a new tag of its own. The cookie should be silently discarded. The
1288 // endpoint SHOULD NOT change states and should leave any timers
1289 // running."
1290 RTC_DLOG(LS_VERBOSE)
1291 << log_prefix()
1292 << "Received COOKIE-ECHO indicating a late COOKIE-ECHO. Discarding";
1293 return false;
1294 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1295 tcb_->peer_verification_tag() == cookie.initiate_tag()) {
1296 // "D) When both local and remote tags match, the endpoint should enter
1297 // the ESTABLISHED state, if it is in the COOKIE-ECHOED state. It
1298 // should stop any cookie timer that may be running and send a COOKIE
1299 // ACK."
1300 RTC_DLOG(LS_VERBOSE)
1301 << log_prefix()
1302 << "Received duplicate COOKIE-ECHO, probably because of peer not "
1303 "receiving COOKIE-ACK and retransmitting COOKIE-ECHO. Continuing.";
1304 }
1305 return true;
1306}
1307
1308void DcSctpSocket::HandleCookieAck(
1309 const CommonHeader& header,
1310 const SctpPacket::ChunkDescriptor& descriptor) {
1311 absl::optional<CookieAckChunk> chunk = CookieAckChunk::Parse(descriptor.data);
1312 if (!ValidateParseSuccess(chunk)) {
1313 return;
1314 }
1315
1316 if (state_ != State::kCookieEchoed) {
1317 // https://tools.ietf.org/html/rfc4960#section-5.2.5
1318 // "At any state other than COOKIE-ECHOED, an endpoint should silently
1319 // discard a received COOKIE ACK chunk."
1320 RTC_DLOG(LS_VERBOSE) << log_prefix()
1321 << "Received COOKIE_ACK not in COOKIE_ECHOED state";
1322 return;
1323 }
1324
1325 // RFC 4960, Errata ID: 4400
1326 t1_cookie_->Stop();
Victor Boiviec20f1562021-06-16 12:52:42 +02001327 tcb_->ClearCookieEchoChunk();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001328 SetState(State::kEstablished, "COOKIE_ACK received");
Victor Boivied3b186e2021-05-05 16:22:29 +02001329 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001330 callbacks_.OnConnected();
1331}
1332
1333void DcSctpSocket::DeliverReassembledMessages() {
1334 if (tcb_->reassembly_queue().HasMessages()) {
1335 for (auto& message : tcb_->reassembly_queue().FlushMessages()) {
Victor Boivied4716ea2021-08-09 12:26:32 +02001336 ++metrics_.rx_messages_count;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001337 callbacks_.OnMessageReceived(std::move(message));
1338 }
1339 }
1340}
1341
1342void DcSctpSocket::HandleSack(const CommonHeader& header,
1343 const SctpPacket::ChunkDescriptor& descriptor) {
1344 absl::optional<SackChunk> chunk = SackChunk::Parse(descriptor.data);
1345
1346 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
Victor Boivied3b186e2021-05-05 16:22:29 +02001347 TimeMs now = callbacks_.TimeMillis();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001348 SackChunk sack = ChunkValidators::Clean(*std::move(chunk));
1349
Victor Boivied3b186e2021-05-05 16:22:29 +02001350 if (tcb_->retransmission_queue().HandleSack(now, sack)) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001351 MaybeSendShutdownOrAck();
1352 // Receiving an ACK will decrease outstanding bytes (maybe now below
1353 // cwnd?) or indicate packet loss that may result in sending FORWARD-TSN.
Victor Boivied3b186e2021-05-05 16:22:29 +02001354 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001355 } else {
1356 RTC_DLOG(LS_VERBOSE) << log_prefix()
1357 << "Dropping out-of-order SACK with TSN "
1358 << *sack.cumulative_tsn_ack();
1359 }
1360 }
1361}
1362
1363void DcSctpSocket::HandleHeartbeatRequest(
1364 const CommonHeader& header,
1365 const SctpPacket::ChunkDescriptor& descriptor) {
1366 absl::optional<HeartbeatRequestChunk> chunk =
1367 HeartbeatRequestChunk::Parse(descriptor.data);
1368
1369 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1370 tcb_->heartbeat_handler().HandleHeartbeatRequest(*std::move(chunk));
1371 }
1372}
1373
1374void DcSctpSocket::HandleHeartbeatAck(
1375 const CommonHeader& header,
1376 const SctpPacket::ChunkDescriptor& descriptor) {
1377 absl::optional<HeartbeatAckChunk> chunk =
1378 HeartbeatAckChunk::Parse(descriptor.data);
1379
1380 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1381 tcb_->heartbeat_handler().HandleHeartbeatAck(*std::move(chunk));
1382 }
1383}
1384
1385void DcSctpSocket::HandleAbort(const CommonHeader& header,
1386 const SctpPacket::ChunkDescriptor& descriptor) {
1387 absl::optional<AbortChunk> chunk = AbortChunk::Parse(descriptor.data);
1388 if (ValidateParseSuccess(chunk)) {
1389 std::string error_string = ErrorCausesToString(chunk->error_causes());
1390 if (tcb_ == nullptr) {
1391 // https://tools.ietf.org/html/rfc4960#section-3.3.7
1392 // "If an endpoint receives an ABORT with a format error or no TCB is
1393 // found, it MUST silently discard it."
1394 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ABORT (" << error_string
1395 << ") on a connection with no TCB. Ignoring";
1396 return;
1397 }
1398
1399 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ABORT (" << error_string
1400 << ") - closing connection.";
1401 InternalClose(ErrorKind::kPeerReported, error_string);
1402 }
1403}
1404
1405void DcSctpSocket::HandleError(const CommonHeader& header,
1406 const SctpPacket::ChunkDescriptor& descriptor) {
1407 absl::optional<ErrorChunk> chunk = ErrorChunk::Parse(descriptor.data);
1408 if (ValidateParseSuccess(chunk)) {
1409 std::string error_string = ErrorCausesToString(chunk->error_causes());
1410 if (tcb_ == nullptr) {
1411 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ERROR (" << error_string
1412 << ") on a connection with no TCB. Ignoring";
1413 return;
1414 }
1415
1416 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ERROR: " << error_string;
1417 callbacks_.OnError(ErrorKind::kPeerReported,
1418 "Peer reported error: " + error_string);
1419 }
1420}
1421
1422void DcSctpSocket::HandleReconfig(
1423 const CommonHeader& header,
1424 const SctpPacket::ChunkDescriptor& descriptor) {
1425 absl::optional<ReConfigChunk> chunk = ReConfigChunk::Parse(descriptor.data);
1426 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1427 tcb_->stream_reset_handler().HandleReConfig(*std::move(chunk));
1428 }
1429}
1430
1431void DcSctpSocket::HandleShutdown(
1432 const CommonHeader& header,
1433 const SctpPacket::ChunkDescriptor& descriptor) {
1434 if (!ValidateParseSuccess(ShutdownChunk::Parse(descriptor.data))) {
1435 return;
1436 }
1437
1438 if (state_ == State::kClosed) {
1439 return;
1440 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1441 // https://tools.ietf.org/html/rfc4960#section-9.2
1442 // "If a SHUTDOWN is received in the COOKIE-WAIT or COOKIE ECHOED state,
1443 // the SHUTDOWN chunk SHOULD be silently discarded."
1444 } else if (state_ == State::kShutdownSent) {
1445 // https://tools.ietf.org/html/rfc4960#section-9.2
1446 // "If an endpoint is in the SHUTDOWN-SENT state and receives a
1447 // SHUTDOWN chunk from its peer, the endpoint shall respond immediately
1448 // with a SHUTDOWN ACK to its peer, and move into the SHUTDOWN-ACK-SENT
1449 // state restarting its T2-shutdown timer."
1450 SendShutdownAck();
1451 SetState(State::kShutdownAckSent, "SHUTDOWN received");
Victor Boivie50a0b122021-05-06 21:07:49 +02001452 } else if (state_ == State::kShutdownAckSent) {
1453 // TODO(webrtc:12739): This condition should be removed and handled by the
1454 // next (state_ != State::kShutdownReceived).
1455 return;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001456 } else if (state_ != State::kShutdownReceived) {
1457 RTC_DLOG(LS_VERBOSE) << log_prefix()
1458 << "Received SHUTDOWN - shutting down the socket";
1459 // https://tools.ietf.org/html/rfc4960#section-9.2
1460 // "Upon reception of the SHUTDOWN, the peer endpoint shall enter the
1461 // SHUTDOWN-RECEIVED state, stop accepting new data from its SCTP user,
1462 // and verify, by checking the Cumulative TSN Ack field of the chunk, that
1463 // all its outstanding DATA chunks have been received by the SHUTDOWN
1464 // sender."
1465 SetState(State::kShutdownReceived, "SHUTDOWN received");
1466 MaybeSendShutdownOrAck();
1467 }
1468}
1469
1470void DcSctpSocket::HandleShutdownAck(
1471 const CommonHeader& header,
1472 const SctpPacket::ChunkDescriptor& descriptor) {
1473 if (!ValidateParseSuccess(ShutdownAckChunk::Parse(descriptor.data))) {
1474 return;
1475 }
1476
1477 if (state_ == State::kShutdownSent || state_ == State::kShutdownAckSent) {
1478 // https://tools.ietf.org/html/rfc4960#section-9.2
1479 // "Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall stop
1480 // the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its peer, and
1481 // remove all record of the association."
1482
1483 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives a
1484 // SHUTDOWN ACK, it shall stop the T2-shutdown timer, send a SHUTDOWN
1485 // COMPLETE chunk to its peer, and remove all record of the association."
1486
1487 SctpPacket::Builder b = tcb_->PacketBuilder();
1488 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/false));
Victor Boivieabf61882021-08-12 15:57:49 +02001489 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001490 InternalClose(ErrorKind::kNoError, "");
1491 } else {
1492 // https://tools.ietf.org/html/rfc4960#section-8.5.1
1493 // "If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state
1494 // the procedures in Section 8.4 SHOULD be followed; in other words, it
1495 // should be treated as an Out Of The Blue packet."
1496
1497 // https://tools.ietf.org/html/rfc4960#section-8.4
1498 // "If the packet contains a SHUTDOWN ACK chunk, the receiver
1499 // should respond to the sender of the OOTB packet with a SHUTDOWN
1500 // COMPLETE. When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
1501 // packet must fill in the Verification Tag field of the outbound packet
1502 // with the Verification Tag received in the SHUTDOWN ACK and set the T
1503 // bit in the Chunk Flags to indicate that the Verification Tag is
1504 // reflected."
1505
1506 SctpPacket::Builder b(header.verification_tag, options_);
1507 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/true));
Victor Boivieabf61882021-08-12 15:57:49 +02001508 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001509 }
1510}
1511
1512void DcSctpSocket::HandleShutdownComplete(
1513 const CommonHeader& header,
1514 const SctpPacket::ChunkDescriptor& descriptor) {
1515 if (!ValidateParseSuccess(ShutdownCompleteChunk::Parse(descriptor.data))) {
1516 return;
1517 }
1518
1519 if (state_ == State::kShutdownAckSent) {
1520 // https://tools.ietf.org/html/rfc4960#section-9.2
1521 // "Upon reception of the SHUTDOWN COMPLETE chunk, the endpoint will
1522 // verify that it is in the SHUTDOWN-ACK-SENT state; if it is not, the
1523 // chunk should be discarded. If the endpoint is in the SHUTDOWN-ACK-SENT
1524 // state, the endpoint should stop the T2-shutdown timer and remove all
1525 // knowledge of the association (and thus the association enters the
1526 // CLOSED state)."
1527 InternalClose(ErrorKind::kNoError, "");
1528 }
1529}
1530
1531void DcSctpSocket::HandleForwardTsn(
1532 const CommonHeader& header,
1533 const SctpPacket::ChunkDescriptor& descriptor) {
1534 absl::optional<ForwardTsnChunk> chunk =
1535 ForwardTsnChunk::Parse(descriptor.data);
1536 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1537 HandleForwardTsnCommon(*chunk);
1538 }
1539}
1540
1541void DcSctpSocket::HandleIForwardTsn(
1542 const CommonHeader& header,
1543 const SctpPacket::ChunkDescriptor& descriptor) {
1544 absl::optional<IForwardTsnChunk> chunk =
1545 IForwardTsnChunk::Parse(descriptor.data);
1546 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1547 HandleForwardTsnCommon(*chunk);
1548 }
1549}
1550
1551void DcSctpSocket::HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk) {
1552 if (!tcb_->capabilities().partial_reliability) {
1553 SctpPacket::Builder b = tcb_->PacketBuilder();
1554 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
1555 Parameters::Builder()
1556 .Add(ProtocolViolationCause(
1557 "I-FORWARD-TSN received, but not indicated "
1558 "during connection establishment"))
1559 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001560 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001561
1562 callbacks_.OnError(ErrorKind::kProtocolViolation,
1563 "Received a FORWARD_TSN without announced peer support");
1564 return;
1565 }
1566 tcb_->data_tracker().HandleForwardTsn(chunk.new_cumulative_tsn());
1567 tcb_->reassembly_queue().Handle(chunk);
1568 // A forward TSN - for ordered streams - may allow messages to be
1569 // delivered.
1570 DeliverReassembledMessages();
1571
1572 // Processing a FORWARD_TSN might result in sending a SACK.
1573 tcb_->MaybeSendSack();
1574}
1575
1576void DcSctpSocket::MaybeSendShutdownOrAck() {
1577 if (tcb_->retransmission_queue().outstanding_bytes() != 0) {
1578 return;
1579 }
1580
1581 if (state_ == State::kShutdownPending) {
1582 // https://tools.ietf.org/html/rfc4960#section-9.2
1583 // "Once all its outstanding data has been acknowledged, the endpoint
1584 // shall send a SHUTDOWN chunk to its peer including in the Cumulative TSN
1585 // Ack field the last sequential TSN it has received from the peer. It
1586 // shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT
1587 // state.""
1588
1589 SendShutdown();
1590 t2_shutdown_->set_duration(tcb_->current_rto());
1591 t2_shutdown_->Start();
1592 SetState(State::kShutdownSent, "No more outstanding data");
1593 } else if (state_ == State::kShutdownReceived) {
1594 // https://tools.ietf.org/html/rfc4960#section-9.2
1595 // "If the receiver of the SHUTDOWN has no more outstanding DATA
1596 // chunks, the SHUTDOWN receiver MUST send a SHUTDOWN ACK and start a
1597 // T2-shutdown timer of its own, entering the SHUTDOWN-ACK-SENT state. If
1598 // the timer expires, the endpoint must resend the SHUTDOWN ACK."
1599
1600 SendShutdownAck();
1601 SetState(State::kShutdownAckSent, "No more outstanding data");
1602 }
1603}
1604
1605void DcSctpSocket::SendShutdown() {
1606 SctpPacket::Builder b = tcb_->PacketBuilder();
1607 b.Add(ShutdownChunk(tcb_->data_tracker().last_cumulative_acked_tsn()));
Victor Boivieabf61882021-08-12 15:57:49 +02001608 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001609}
1610
1611void DcSctpSocket::SendShutdownAck() {
Victor Boivieabf61882021-08-12 15:57:49 +02001612 packet_sender_.Send(tcb_->PacketBuilder().Add(ShutdownAckChunk()));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001613 t2_shutdown_->set_duration(tcb_->current_rto());
1614 t2_shutdown_->Start();
1615}
1616
Sergey Sukhanov43972812021-09-17 15:32:48 +02001617HandoverReadinessStatus DcSctpSocket::GetHandoverReadiness() const {
1618 HandoverReadinessStatus status;
1619 if (state_ != State::kClosed && state_ != State::kEstablished) {
1620 status.Add(HandoverUnreadinessReason::kWrongConnectionState);
1621 }
1622 if (!send_queue_.IsEmpty()) {
1623 status.Add(HandoverUnreadinessReason::kSendQueueNotEmpty);
1624 }
1625 if (tcb_) {
1626 status.Add(tcb_->GetHandoverReadiness());
1627 }
1628 return status;
1629}
1630
1631absl::optional<DcSctpSocketHandoverState>
1632DcSctpSocket::GetHandoverStateAndClose() {
1633 if (!GetHandoverReadiness().IsReady()) {
1634 return absl::nullopt;
1635 }
1636
1637 DcSctpSocketHandoverState state;
1638
1639 if (state_ == State::kClosed) {
1640 state.socket_state = DcSctpSocketHandoverState::SocketState::kClosed;
1641 } else if (state_ == State::kEstablished) {
1642 state.socket_state = DcSctpSocketHandoverState::SocketState::kConnected;
1643 tcb_->AddHandoverState(state);
1644 InternalClose(ErrorKind::kNoError, "handover");
1645 callbacks_.TriggerDeferred();
1646 }
1647
1648 return std::move(state);
1649}
1650
Victor Boivieb6580cc2021-04-08 09:56:59 +02001651} // namespace dcsctp