blob: 7910a3953f9ab0b9c7f781fc80744f61325a9215 [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
Sergey Sukhanov72435322021-09-21 13:31:09 +0200305 send_queue_.RestoreFromState(state);
306
Sergey Sukhanov43972812021-09-17 15:32:48 +0200307 tcb_ = std::make_unique<TransmissionControlBlock>(
308 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
309 send_queue_, my_verification_tag, TSN(state.my_initial_tsn),
310 VerificationTag(state.peer_verification_tag),
311 TSN(state.peer_initial_tsn), static_cast<size_t>(0),
312 TieTag(state.tie_tag), packet_sender_,
313 [this]() { return state_ == State::kEstablished; }, &state);
314 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Created peer TCB from state: "
315 << tcb_->ToString();
316
317 SetState(State::kEstablished, "restored from handover state");
318 callbacks_.OnConnected();
319 }
320 }
321
322 RTC_DCHECK(IsConsistent());
323 callbacks_.TriggerDeferred();
324}
325
Victor Boivieb6580cc2021-04-08 09:56:59 +0200326void DcSctpSocket::Shutdown() {
327 if (tcb_ != nullptr) {
328 // https://tools.ietf.org/html/rfc4960#section-9.2
329 // "Upon receipt of the SHUTDOWN primitive from its upper layer, the
330 // endpoint enters the SHUTDOWN-PENDING state and remains there until all
331 // outstanding data has been acknowledged by its peer."
Victor Boivie50a0b122021-05-06 21:07:49 +0200332
333 // TODO(webrtc:12739): Remove this check, as it just hides the problem that
334 // the socket can transition from ShutdownSent to ShutdownPending, or
335 // ShutdownAckSent to ShutdownPending which is illegal.
336 if (state_ != State::kShutdownSent && state_ != State::kShutdownAckSent) {
337 SetState(State::kShutdownPending, "Shutdown called");
338 t1_init_->Stop();
339 t1_cookie_->Stop();
340 MaybeSendShutdownOrAck();
341 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200342 } else {
343 // Connection closed before even starting to connect, or during the initial
344 // connection phase. There is no outstanding data, so the socket can just
345 // be closed (stopping any connection timers, if any), as this is the
346 // client's intention, by calling Shutdown.
347 InternalClose(ErrorKind::kNoError, "");
348 }
349 RTC_DCHECK(IsConsistent());
350 callbacks_.TriggerDeferred();
351}
352
353void DcSctpSocket::Close() {
354 if (state_ != State::kClosed) {
355 if (tcb_ != nullptr) {
356 SctpPacket::Builder b = tcb_->PacketBuilder();
357 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
358 Parameters::Builder()
359 .Add(UserInitiatedAbortCause("Close called"))
360 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +0200361 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200362 }
363 InternalClose(ErrorKind::kNoError, "");
364 } else {
365 RTC_DLOG(LS_INFO) << log_prefix() << "Called Close on a closed socket";
366 }
367 RTC_DCHECK(IsConsistent());
368 callbacks_.TriggerDeferred();
369}
370
371void DcSctpSocket::CloseConnectionBecauseOfTooManyTransmissionErrors() {
Victor Boivieabf61882021-08-12 15:57:49 +0200372 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200373 true, Parameters::Builder()
374 .Add(UserInitiatedAbortCause("Too many retransmissions"))
375 .Build())));
376 InternalClose(ErrorKind::kTooManyRetries, "Too many retransmissions");
377}
378
379void DcSctpSocket::InternalClose(ErrorKind error, absl::string_view message) {
380 if (state_ != State::kClosed) {
381 t1_init_->Stop();
382 t1_cookie_->Stop();
383 t2_shutdown_->Stop();
384 tcb_ = nullptr;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200385
386 if (error == ErrorKind::kNoError) {
387 callbacks_.OnClosed();
388 } else {
389 callbacks_.OnAborted(error, message);
390 }
391 SetState(State::kClosed, message);
392 }
393 // This method's purpose is to abort/close and make it consistent by ensuring
394 // that e.g. all timers really are stopped.
395 RTC_DCHECK(IsConsistent());
396}
397
398SendStatus DcSctpSocket::Send(DcSctpMessage message,
399 const SendOptions& send_options) {
400 if (message.payload().empty()) {
401 callbacks_.OnError(ErrorKind::kProtocolViolation,
402 "Unable to send empty message");
403 return SendStatus::kErrorMessageEmpty;
404 }
405 if (message.payload().size() > options_.max_message_size) {
406 callbacks_.OnError(ErrorKind::kProtocolViolation,
407 "Unable to send too large message");
408 return SendStatus::kErrorMessageTooLarge;
409 }
410 if (state_ == State::kShutdownPending || state_ == State::kShutdownSent ||
411 state_ == State::kShutdownReceived || state_ == State::kShutdownAckSent) {
412 // https://tools.ietf.org/html/rfc4960#section-9.2
413 // "An endpoint should reject any new data request from its upper layer
414 // if it is in the SHUTDOWN-PENDING, SHUTDOWN-SENT, SHUTDOWN-RECEIVED, or
415 // SHUTDOWN-ACK-SENT state."
416 callbacks_.OnError(ErrorKind::kWrongSequence,
417 "Unable to send message as the socket is shutting down");
418 return SendStatus::kErrorShuttingDown;
419 }
420 if (send_queue_.IsFull()) {
421 callbacks_.OnError(ErrorKind::kResourceExhaustion,
422 "Unable to send message as the send queue is full");
423 return SendStatus::kErrorResourceExhaustion;
424 }
425
Victor Boivied3b186e2021-05-05 16:22:29 +0200426 TimeMs now = callbacks_.TimeMillis();
Victor Boivied4716ea2021-08-09 12:26:32 +0200427 ++metrics_.tx_messages_count;
Victor Boivied3b186e2021-05-05 16:22:29 +0200428 send_queue_.Add(now, std::move(message), send_options);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200429 if (tcb_ != nullptr) {
Victor Boivied3b186e2021-05-05 16:22:29 +0200430 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200431 }
432
433 RTC_DCHECK(IsConsistent());
434 callbacks_.TriggerDeferred();
435 return SendStatus::kSuccess;
436}
437
438ResetStreamsStatus DcSctpSocket::ResetStreams(
439 rtc::ArrayView<const StreamID> outgoing_streams) {
440 if (tcb_ == nullptr) {
441 callbacks_.OnError(ErrorKind::kWrongSequence,
442 "Can't reset streams as the socket is not connected");
443 return ResetStreamsStatus::kNotConnected;
444 }
445 if (!tcb_->capabilities().reconfig) {
446 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
447 "Can't reset streams as the peer doesn't support it");
448 return ResetStreamsStatus::kNotSupported;
449 }
450
451 tcb_->stream_reset_handler().ResetStreams(outgoing_streams);
452 absl::optional<ReConfigChunk> reconfig =
453 tcb_->stream_reset_handler().MakeStreamResetRequest();
454 if (reconfig.has_value()) {
455 SctpPacket::Builder builder = tcb_->PacketBuilder();
456 builder.Add(*reconfig);
Victor Boivieabf61882021-08-12 15:57:49 +0200457 packet_sender_.Send(builder);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200458 }
459
460 RTC_DCHECK(IsConsistent());
461 callbacks_.TriggerDeferred();
462 return ResetStreamsStatus::kPerformed;
463}
464
465SocketState DcSctpSocket::state() const {
466 switch (state_) {
467 case State::kClosed:
468 return SocketState::kClosed;
469 case State::kCookieWait:
470 ABSL_FALLTHROUGH_INTENDED;
471 case State::kCookieEchoed:
472 return SocketState::kConnecting;
473 case State::kEstablished:
474 return SocketState::kConnected;
475 case State::kShutdownPending:
476 ABSL_FALLTHROUGH_INTENDED;
477 case State::kShutdownSent:
478 ABSL_FALLTHROUGH_INTENDED;
479 case State::kShutdownReceived:
480 ABSL_FALLTHROUGH_INTENDED;
481 case State::kShutdownAckSent:
482 return SocketState::kShuttingDown;
483 }
484}
485
Florent Castelli0810b052021-05-04 20:12:52 +0200486void DcSctpSocket::SetMaxMessageSize(size_t max_message_size) {
487 options_.max_message_size = max_message_size;
488}
489
Victor Boivie236ac502021-05-20 19:34:18 +0200490size_t DcSctpSocket::buffered_amount(StreamID stream_id) const {
491 return send_queue_.buffered_amount(stream_id);
492}
493
494size_t DcSctpSocket::buffered_amount_low_threshold(StreamID stream_id) const {
495 return send_queue_.buffered_amount_low_threshold(stream_id);
496}
497
498void DcSctpSocket::SetBufferedAmountLowThreshold(StreamID stream_id,
499 size_t bytes) {
500 send_queue_.SetBufferedAmountLowThreshold(stream_id, bytes);
501}
502
Victor Boivied4716ea2021-08-09 12:26:32 +0200503Metrics DcSctpSocket::GetMetrics() const {
504 Metrics metrics = metrics_;
505
506 if (tcb_ != nullptr) {
507 // Update the metrics with some stats that are extracted from
508 // sub-components.
509 metrics.cwnd_bytes = tcb_->cwnd();
510 metrics.srtt_ms = tcb_->current_srtt().value();
511 size_t packet_payload_size =
512 options_.mtu - SctpPacket::kHeaderSize - DataChunk::kHeaderSize;
513 metrics.unack_data_count =
514 tcb_->retransmission_queue().outstanding_items() +
515 (send_queue_.total_buffered_amount() + packet_payload_size - 1) /
516 packet_payload_size;
517 metrics.peer_rwnd_bytes = tcb_->retransmission_queue().rwnd();
518 }
519
520 return metrics;
521}
522
Victor Boivieb6580cc2021-04-08 09:56:59 +0200523void DcSctpSocket::MaybeSendShutdownOnPacketReceived(const SctpPacket& packet) {
524 if (state_ == State::kShutdownSent) {
525 bool has_data_chunk =
526 std::find_if(packet.descriptors().begin(), packet.descriptors().end(),
527 [](const SctpPacket::ChunkDescriptor& descriptor) {
528 return descriptor.type == DataChunk::kType;
529 }) != packet.descriptors().end();
530 if (has_data_chunk) {
531 // https://tools.ietf.org/html/rfc4960#section-9.2
532 // "While in the SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately
533 // respond to each received packet containing one or more DATA chunks with
534 // a SHUTDOWN chunk and restart the T2-shutdown timer.""
535 SendShutdown();
536 t2_shutdown_->set_duration(tcb_->current_rto());
537 t2_shutdown_->Start();
538 }
539 }
540}
541
542bool DcSctpSocket::ValidatePacket(const SctpPacket& packet) {
543 const CommonHeader& header = packet.common_header();
544 VerificationTag my_verification_tag =
545 tcb_ != nullptr ? tcb_->my_verification_tag() : VerificationTag(0);
546
547 if (header.verification_tag == VerificationTag(0)) {
548 if (packet.descriptors().size() == 1 &&
549 packet.descriptors()[0].type == InitChunk::kType) {
550 // https://tools.ietf.org/html/rfc4960#section-8.5.1
551 // "When an endpoint receives an SCTP packet with the Verification Tag
552 // set to 0, it should verify that the packet contains only an INIT chunk.
553 // Otherwise, the receiver MUST silently discard the packet.""
554 return true;
555 }
556 callbacks_.OnError(
557 ErrorKind::kParseFailed,
558 "Only a single INIT chunk can be present in packets sent on "
559 "verification_tag = 0");
560 return false;
561 }
562
563 if (packet.descriptors().size() == 1 &&
564 packet.descriptors()[0].type == AbortChunk::kType) {
565 // https://tools.ietf.org/html/rfc4960#section-8.5.1
566 // "The receiver of an ABORT MUST accept the packet if the Verification
567 // Tag field of the packet matches its own tag and the T bit is not set OR
568 // if it is set to its peer's tag and the T bit is set in the Chunk Flags.
569 // Otherwise, the receiver MUST silently discard the packet and take no
570 // further action."
571 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
572 if (t_bit && tcb_ == nullptr) {
573 // Can't verify the tag - assume it's okey.
574 return true;
575 }
576 if ((!t_bit && header.verification_tag == my_verification_tag) ||
577 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
578 return true;
579 }
580 callbacks_.OnError(ErrorKind::kParseFailed,
581 "ABORT chunk verification tag was wrong");
582 return false;
583 }
584
585 if (packet.descriptors()[0].type == InitAckChunk::kType) {
586 if (header.verification_tag == connect_params_.verification_tag) {
587 return true;
588 }
589 callbacks_.OnError(
590 ErrorKind::kParseFailed,
591 rtc::StringFormat(
592 "Packet has invalid verification tag: %08x, expected %08x",
593 *header.verification_tag, *connect_params_.verification_tag));
594 return false;
595 }
596
597 if (packet.descriptors()[0].type == CookieEchoChunk::kType) {
598 // Handled in chunk handler (due to RFC 4960, section 5.2.4).
599 return true;
600 }
601
602 if (packet.descriptors().size() == 1 &&
603 packet.descriptors()[0].type == ShutdownCompleteChunk::kType) {
604 // https://tools.ietf.org/html/rfc4960#section-8.5.1
605 // "The receiver of a SHUTDOWN COMPLETE shall accept the packet if the
606 // Verification Tag field of the packet matches its own tag and the T bit is
607 // not set OR if it is set to its peer's tag and the T bit is set in the
608 // Chunk Flags. Otherwise, the receiver MUST silently discard the packet
609 // and take no further action."
610 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
611 if (t_bit && tcb_ == nullptr) {
612 // Can't verify the tag - assume it's okey.
613 return true;
614 }
615 if ((!t_bit && header.verification_tag == my_verification_tag) ||
616 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
617 return true;
618 }
619 callbacks_.OnError(ErrorKind::kParseFailed,
620 "SHUTDOWN_COMPLETE chunk verification tag was wrong");
621 return false;
622 }
623
624 // https://tools.ietf.org/html/rfc4960#section-8.5
625 // "When receiving an SCTP packet, the endpoint MUST ensure that the value
626 // in the Verification Tag field of the received SCTP packet matches its own
627 // tag. If the received Verification Tag value does not match the receiver's
628 // own tag value, the receiver shall silently discard the packet and shall not
629 // process it any further..."
630 if (header.verification_tag == my_verification_tag) {
631 return true;
632 }
633
634 callbacks_.OnError(
635 ErrorKind::kParseFailed,
636 rtc::StringFormat(
637 "Packet has invalid verification tag: %08x, expected %08x",
638 *header.verification_tag, *my_verification_tag));
639 return false;
640}
641
642void DcSctpSocket::HandleTimeout(TimeoutID timeout_id) {
643 timer_manager_.HandleTimeout(timeout_id);
644
645 if (tcb_ != nullptr && tcb_->HasTooManyTxErrors()) {
646 // Tearing down the TCB has to be done outside the handlers.
647 CloseConnectionBecauseOfTooManyTransmissionErrors();
648 }
649
650 RTC_DCHECK(IsConsistent());
651 callbacks_.TriggerDeferred();
652}
653
654void DcSctpSocket::ReceivePacket(rtc::ArrayView<const uint8_t> data) {
Victor Boivied4716ea2021-08-09 12:26:32 +0200655 ++metrics_.rx_packets_count;
656
Victor Boivieb6580cc2021-04-08 09:56:59 +0200657 if (packet_observer_ != nullptr) {
658 packet_observer_->OnReceivedPacket(callbacks_.TimeMillis(), data);
659 }
660
661 absl::optional<SctpPacket> packet =
662 SctpPacket::Parse(data, options_.disable_checksum_verification);
663 if (!packet.has_value()) {
664 // https://tools.ietf.org/html/rfc4960#section-6.8
665 // "The default procedure for handling invalid SCTP packets is to
666 // silently discard them."
667 callbacks_.OnError(ErrorKind::kParseFailed,
668 "Failed to parse received SCTP packet");
669 RTC_DCHECK(IsConsistent());
670 callbacks_.TriggerDeferred();
671 return;
672 }
673
674 if (RTC_DLOG_IS_ON) {
675 for (const auto& descriptor : packet->descriptors()) {
676 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received "
677 << DebugConvertChunkToString(descriptor.data);
678 }
679 }
680
681 if (!ValidatePacket(*packet)) {
682 RTC_DLOG(LS_VERBOSE) << log_prefix()
683 << "Packet failed verification tag check - dropping";
684 RTC_DCHECK(IsConsistent());
685 callbacks_.TriggerDeferred();
686 return;
687 }
688
689 MaybeSendShutdownOnPacketReceived(*packet);
690
691 for (const auto& descriptor : packet->descriptors()) {
692 if (!Dispatch(packet->common_header(), descriptor)) {
693 break;
694 }
695 }
696
697 if (tcb_ != nullptr) {
698 tcb_->data_tracker().ObservePacketEnd();
699 tcb_->MaybeSendSack();
700 }
701
702 RTC_DCHECK(IsConsistent());
703 callbacks_.TriggerDeferred();
704}
705
706void DcSctpSocket::DebugPrintOutgoing(rtc::ArrayView<const uint8_t> payload) {
707 auto packet = SctpPacket::Parse(payload);
708 RTC_DCHECK(packet.has_value());
709
710 for (const auto& desc : packet->descriptors()) {
711 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Sent "
712 << DebugConvertChunkToString(desc.data);
713 }
714}
715
716bool DcSctpSocket::Dispatch(const CommonHeader& header,
717 const SctpPacket::ChunkDescriptor& descriptor) {
718 switch (descriptor.type) {
719 case DataChunk::kType:
720 HandleData(header, descriptor);
721 break;
722 case InitChunk::kType:
723 HandleInit(header, descriptor);
724 break;
725 case InitAckChunk::kType:
726 HandleInitAck(header, descriptor);
727 break;
728 case SackChunk::kType:
729 HandleSack(header, descriptor);
730 break;
731 case HeartbeatRequestChunk::kType:
732 HandleHeartbeatRequest(header, descriptor);
733 break;
734 case HeartbeatAckChunk::kType:
735 HandleHeartbeatAck(header, descriptor);
736 break;
737 case AbortChunk::kType:
738 HandleAbort(header, descriptor);
739 break;
740 case ErrorChunk::kType:
741 HandleError(header, descriptor);
742 break;
743 case CookieEchoChunk::kType:
744 HandleCookieEcho(header, descriptor);
745 break;
746 case CookieAckChunk::kType:
747 HandleCookieAck(header, descriptor);
748 break;
749 case ShutdownChunk::kType:
750 HandleShutdown(header, descriptor);
751 break;
752 case ShutdownAckChunk::kType:
753 HandleShutdownAck(header, descriptor);
754 break;
755 case ShutdownCompleteChunk::kType:
756 HandleShutdownComplete(header, descriptor);
757 break;
758 case ReConfigChunk::kType:
759 HandleReconfig(header, descriptor);
760 break;
761 case ForwardTsnChunk::kType:
762 HandleForwardTsn(header, descriptor);
763 break;
764 case IDataChunk::kType:
765 HandleIData(header, descriptor);
766 break;
767 case IForwardTsnChunk::kType:
768 HandleForwardTsn(header, descriptor);
769 break;
770 default:
771 return HandleUnrecognizedChunk(descriptor);
772 }
773 return true;
774}
775
776bool DcSctpSocket::HandleUnrecognizedChunk(
777 const SctpPacket::ChunkDescriptor& descriptor) {
778 bool report_as_error = (descriptor.type & 0x40) != 0;
779 bool continue_processing = (descriptor.type & 0x80) != 0;
780 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received unknown chunk: "
781 << static_cast<int>(descriptor.type);
782 if (report_as_error) {
783 rtc::StringBuilder sb;
784 sb << "Received unknown chunk of type: "
785 << static_cast<int>(descriptor.type) << " with report-error bit set";
786 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
787 RTC_DLOG(LS_VERBOSE)
788 << log_prefix()
789 << "Unknown chunk, with type indicating it should be reported.";
790
791 // https://tools.ietf.org/html/rfc4960#section-3.2
792 // "... report in an ERROR chunk using the 'Unrecognized Chunk Type'
793 // cause."
794 if (tcb_ != nullptr) {
795 // Need TCB - this chunk must be sent with a correct verification tag.
Victor Boivieabf61882021-08-12 15:57:49 +0200796 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200797 ErrorChunk(Parameters::Builder()
798 .Add(UnrecognizedChunkTypeCause(std::vector<uint8_t>(
799 descriptor.data.begin(), descriptor.data.end())))
800 .Build())));
801 }
802 }
803 if (!continue_processing) {
804 // https://tools.ietf.org/html/rfc4960#section-3.2
805 // "Stop processing this SCTP packet and discard it, do not process any
806 // further chunks within it."
807 RTC_DLOG(LS_VERBOSE) << log_prefix()
808 << "Unknown chunk, with type indicating not to "
809 "process any further chunks";
810 }
811
812 return continue_processing;
813}
814
815absl::optional<DurationMs> DcSctpSocket::OnInitTimerExpiry() {
816 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_init_->name()
817 << " has expired: " << t1_init_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200818 << "/" << t1_init_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200819 RTC_DCHECK(state_ == State::kCookieWait);
820
821 if (t1_init_->is_running()) {
822 SendInit();
823 } else {
824 InternalClose(ErrorKind::kTooManyRetries, "No INIT_ACK received");
825 }
826 RTC_DCHECK(IsConsistent());
827 return absl::nullopt;
828}
829
830absl::optional<DurationMs> DcSctpSocket::OnCookieTimerExpiry() {
831 // https://tools.ietf.org/html/rfc4960#section-4
832 // "If the T1-cookie timer expires, the endpoint MUST retransmit COOKIE
833 // ECHO and restart the T1-cookie timer without changing state. This MUST
834 // be repeated up to 'Max.Init.Retransmits' times. After that, the endpoint
835 // MUST abort the initialization process and report the error to the SCTP
836 // user."
837 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_cookie_->name()
838 << " has expired: " << t1_cookie_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200839 << "/"
840 << t1_cookie_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200841
842 RTC_DCHECK(state_ == State::kCookieEchoed);
843
844 if (t1_cookie_->is_running()) {
Victor Boiviec20f1562021-06-16 12:52:42 +0200845 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200846 } else {
847 InternalClose(ErrorKind::kTooManyRetries, "No COOKIE_ACK received");
848 }
849
850 RTC_DCHECK(IsConsistent());
851 return absl::nullopt;
852}
853
854absl::optional<DurationMs> DcSctpSocket::OnShutdownTimerExpiry() {
855 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t2_shutdown_->name()
856 << " has expired: " << t2_shutdown_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200857 << "/"
858 << t2_shutdown_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200859
Victor Boivie914925f2021-05-07 11:22:50 +0200860 if (!t2_shutdown_->is_running()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +0200861 // https://tools.ietf.org/html/rfc4960#section-9.2
862 // "An endpoint should limit the number of retransmissions of the SHUTDOWN
863 // chunk to the protocol parameter 'Association.Max.Retrans'. If this
864 // threshold is exceeded, the endpoint should destroy the TCB..."
865
Victor Boivieabf61882021-08-12 15:57:49 +0200866 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200867 AbortChunk(true, Parameters::Builder()
868 .Add(UserInitiatedAbortCause(
869 "Too many retransmissions of SHUTDOWN"))
870 .Build())));
871
872 InternalClose(ErrorKind::kTooManyRetries, "No SHUTDOWN_ACK received");
Victor Boivie914925f2021-05-07 11:22:50 +0200873 RTC_DCHECK(IsConsistent());
874 return absl::nullopt;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200875 }
Victor Boivie914925f2021-05-07 11:22:50 +0200876
877 // https://tools.ietf.org/html/rfc4960#section-9.2
878 // "If the timer expires, the endpoint must resend the SHUTDOWN with the
879 // updated last sequential TSN received from its peer."
880 SendShutdown();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200881 RTC_DCHECK(IsConsistent());
882 return tcb_->current_rto();
883}
884
Victor Boivieabf61882021-08-12 15:57:49 +0200885void DcSctpSocket::OnSentPacket(rtc::ArrayView<const uint8_t> packet,
886 SendPacketStatus status) {
887 // The packet observer is invoked even if the packet was failed to be sent, to
888 // indicate an attempt was made.
Victor Boivieb6580cc2021-04-08 09:56:59 +0200889 if (packet_observer_ != nullptr) {
Victor Boivieabf61882021-08-12 15:57:49 +0200890 packet_observer_->OnSentPacket(callbacks_.TimeMillis(), packet);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200891 }
Victor Boivieabf61882021-08-12 15:57:49 +0200892
893 if (status == SendPacketStatus::kSuccess) {
894 if (RTC_DLOG_IS_ON) {
895 DebugPrintOutgoing(packet);
896 }
897
898 // The heartbeat interval timer is restarted for every sent packet, to
899 // fire when the outgoing channel is inactive.
900 if (tcb_ != nullptr) {
901 tcb_->heartbeat_handler().RestartTimer();
902 }
903
904 ++metrics_.tx_packets_count;
905 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200906}
907
908bool DcSctpSocket::ValidateHasTCB() {
909 if (tcb_ != nullptr) {
910 return true;
911 }
912
913 callbacks_.OnError(
914 ErrorKind::kNotConnected,
915 "Received unexpected commands on socket that is not connected");
916 return false;
917}
918
919void DcSctpSocket::ReportFailedToParseChunk(int chunk_type) {
920 rtc::StringBuilder sb;
921 sb << "Failed to parse chunk of type: " << chunk_type;
922 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
923}
924
925void DcSctpSocket::HandleData(const CommonHeader& header,
926 const SctpPacket::ChunkDescriptor& descriptor) {
927 absl::optional<DataChunk> chunk = DataChunk::Parse(descriptor.data);
928 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
929 HandleDataCommon(*chunk);
930 }
931}
932
933void DcSctpSocket::HandleIData(const CommonHeader& header,
934 const SctpPacket::ChunkDescriptor& descriptor) {
935 absl::optional<IDataChunk> chunk = IDataChunk::Parse(descriptor.data);
936 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
937 HandleDataCommon(*chunk);
938 }
939}
940
941void DcSctpSocket::HandleDataCommon(AnyDataChunk& chunk) {
942 TSN tsn = chunk.tsn();
943 AnyDataChunk::ImmediateAckFlag immediate_ack = chunk.options().immediate_ack;
944 Data data = std::move(chunk).extract();
945
946 if (data.payload.empty()) {
947 // Empty DATA chunks are illegal.
Victor Boivieabf61882021-08-12 15:57:49 +0200948 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200949 ErrorChunk(Parameters::Builder().Add(NoUserDataCause(tsn)).Build())));
950 callbacks_.OnError(ErrorKind::kProtocolViolation,
951 "Received DATA chunk with no user data");
952 return;
953 }
954
955 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Handle DATA, queue_size="
956 << tcb_->reassembly_queue().queued_bytes()
957 << ", water_mark="
958 << tcb_->reassembly_queue().watermark_bytes()
959 << ", full=" << tcb_->reassembly_queue().is_full()
960 << ", above="
961 << tcb_->reassembly_queue().is_above_watermark();
962
963 if (tcb_->reassembly_queue().is_full()) {
964 // If the reassembly queue is full, there is nothing that can be done. The
965 // specification only allows dropping gap-ack-blocks, and that's not
966 // likely to help as the socket has been trying to fill gaps since the
967 // watermark was reached.
Victor Boivieabf61882021-08-12 15:57:49 +0200968 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200969 true, Parameters::Builder().Add(OutOfResourceErrorCause()).Build())));
970 InternalClose(ErrorKind::kResourceExhaustion,
971 "Reassembly Queue is exhausted");
972 return;
973 }
974
975 if (tcb_->reassembly_queue().is_above_watermark()) {
976 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Is above high watermark";
977 // If the reassembly queue is above its high watermark, only accept data
978 // chunks that increase its cumulative ack tsn in an attempt to fill gaps
979 // to deliver messages.
980 if (!tcb_->data_tracker().will_increase_cum_ack_tsn(tsn)) {
981 RTC_DLOG(LS_VERBOSE) << log_prefix()
982 << "Rejected data because of exceeding watermark";
983 tcb_->data_tracker().ForceImmediateSack();
984 return;
985 }
986 }
987
988 if (!tcb_->data_tracker().IsTSNValid(tsn)) {
989 RTC_DLOG(LS_VERBOSE) << log_prefix()
990 << "Rejected data because of failing TSN validity";
991 return;
992 }
993
994 tcb_->data_tracker().Observe(tsn, immediate_ack);
995 tcb_->reassembly_queue().MaybeResetStreamsDeferred(
996 tcb_->data_tracker().last_cumulative_acked_tsn());
997 tcb_->reassembly_queue().Add(tsn, std::move(data));
998 DeliverReassembledMessages();
999}
1000
1001void DcSctpSocket::HandleInit(const CommonHeader& header,
1002 const SctpPacket::ChunkDescriptor& descriptor) {
1003 absl::optional<InitChunk> chunk = InitChunk::Parse(descriptor.data);
1004 if (!ValidateParseSuccess(chunk)) {
1005 return;
1006 }
1007
1008 if (chunk->initiate_tag() == VerificationTag(0) ||
1009 chunk->nbr_outbound_streams() == 0 || chunk->nbr_inbound_streams() == 0) {
1010 // https://tools.ietf.org/html/rfc4960#section-3.3.2
1011 // "If the value of the Initiate Tag in a received INIT chunk is found
1012 // to be 0, the receiver MUST treat it as an error and close the
1013 // association by transmitting an ABORT."
1014
1015 // "A receiver of an INIT with the OS value set to 0 SHOULD abort the
1016 // association."
1017
1018 // "A receiver of an INIT with the MIS value of 0 SHOULD abort the
1019 // association."
1020
Victor Boivieabf61882021-08-12 15:57:49 +02001021 packet_sender_.Send(
1022 SctpPacket::Builder(VerificationTag(0), options_)
1023 .Add(AbortChunk(
1024 /*filled_in_verification_tag=*/false,
1025 Parameters::Builder()
1026 .Add(ProtocolViolationCause("INIT malformed"))
1027 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001028 InternalClose(ErrorKind::kProtocolViolation, "Received invalid INIT");
1029 return;
1030 }
1031
1032 if (state_ == State::kShutdownAckSent) {
1033 // https://tools.ietf.org/html/rfc4960#section-9.2
1034 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives an
1035 // INIT chunk (e.g., if the SHUTDOWN COMPLETE was lost) with source and
1036 // destination transport addresses (either in the IP addresses or in the
1037 // INIT chunk) that belong to this association, it should discard the INIT
1038 // chunk and retransmit the SHUTDOWN ACK chunk."
1039 RTC_DLOG(LS_VERBOSE) << log_prefix()
1040 << "Received Init indicating lost ShutdownComplete";
1041 SendShutdownAck();
1042 return;
1043 }
1044
1045 TieTag tie_tag(0);
1046 if (state_ == State::kClosed) {
1047 RTC_DLOG(LS_VERBOSE) << log_prefix()
1048 << "Received Init in closed state (normal)";
1049
1050 MakeConnectionParameters();
1051 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1052 // https://tools.ietf.org/html/rfc4960#section-5.2.1
1053 // "This usually indicates an initialization collision, i.e., each
1054 // endpoint is attempting, at about the same time, to establish an
1055 // association with the other endpoint. Upon receipt of an INIT in the
1056 // COOKIE-WAIT state, an endpoint MUST respond with an INIT ACK using the
1057 // same parameters it sent in its original INIT chunk (including its
1058 // Initiate Tag, unchanged). When responding, the endpoint MUST send the
1059 // INIT ACK back to the same address that the original INIT (sent by this
1060 // endpoint) was sent."
1061 RTC_DLOG(LS_VERBOSE) << log_prefix()
1062 << "Received Init indicating simultaneous connections";
1063 } else {
1064 RTC_DCHECK(tcb_ != nullptr);
1065 // https://tools.ietf.org/html/rfc4960#section-5.2.2
1066 // "The outbound SCTP packet containing this INIT ACK MUST carry a
1067 // Verification Tag value equal to the Initiate Tag found in the
1068 // unexpected INIT. And the INIT ACK MUST contain a new Initiate Tag
1069 // (randomly generated; see Section 5.3.1). Other parameters for the
1070 // endpoint SHOULD be copied from the existing parameters of the
1071 // association (e.g., number of outbound streams) into the INIT ACK and
1072 // cookie."
1073 RTC_DLOG(LS_VERBOSE) << log_prefix()
1074 << "Received Init indicating restarted connection";
1075 // Create a new verification tag - different from the previous one.
1076 for (int tries = 0; tries < 10; ++tries) {
1077 connect_params_.verification_tag = VerificationTag(
1078 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
1079 if (connect_params_.verification_tag != tcb_->my_verification_tag()) {
1080 break;
1081 }
1082 }
1083
1084 // Make the initial TSN make a large jump, so that there is no overlap
1085 // with the old and new association.
1086 connect_params_.initial_tsn =
1087 TSN(*tcb_->retransmission_queue().next_tsn() + 1000000);
1088 tie_tag = tcb_->tie_tag();
1089 }
1090
1091 RTC_DLOG(LS_VERBOSE)
1092 << log_prefix()
1093 << rtc::StringFormat(
1094 "Proceeding with connection. my_verification_tag=%08x, "
1095 "my_initial_tsn=%u, peer_verification_tag=%08x, "
1096 "peer_initial_tsn=%u",
1097 *connect_params_.verification_tag, *connect_params_.initial_tsn,
1098 *chunk->initiate_tag(), *chunk->initial_tsn());
1099
1100 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1101
1102 SctpPacket::Builder b(chunk->initiate_tag(), options_);
1103 Parameters::Builder params_builder =
1104 Parameters::Builder().Add(StateCookieParameter(
1105 StateCookie(chunk->initiate_tag(), chunk->initial_tsn(),
1106 chunk->a_rwnd(), tie_tag, capabilities)
1107 .Serialize()));
1108 AddCapabilityParameters(options_, params_builder);
1109
1110 InitAckChunk init_ack(/*initiate_tag=*/connect_params_.verification_tag,
1111 options_.max_receiver_window_buffer_size,
1112 options_.announced_maximum_outgoing_streams,
1113 options_.announced_maximum_incoming_streams,
1114 connect_params_.initial_tsn, params_builder.Build());
1115 b.Add(init_ack);
Victor Boivieabf61882021-08-12 15:57:49 +02001116 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001117}
1118
Victor Boivieb6580cc2021-04-08 09:56:59 +02001119void DcSctpSocket::HandleInitAck(
1120 const CommonHeader& header,
1121 const SctpPacket::ChunkDescriptor& descriptor) {
1122 absl::optional<InitAckChunk> chunk = InitAckChunk::Parse(descriptor.data);
1123 if (!ValidateParseSuccess(chunk)) {
1124 return;
1125 }
1126
1127 if (state_ != State::kCookieWait) {
1128 // https://tools.ietf.org/html/rfc4960#section-5.2.3
1129 // "If an INIT ACK is received by an endpoint in any state other than
1130 // the COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk."
1131 RTC_DLOG(LS_VERBOSE) << log_prefix()
1132 << "Received INIT_ACK in unexpected state";
1133 return;
1134 }
1135
1136 auto cookie = chunk->parameters().get<StateCookieParameter>();
1137 if (!cookie.has_value()) {
Victor Boivieabf61882021-08-12 15:57:49 +02001138 packet_sender_.Send(
1139 SctpPacket::Builder(connect_params_.verification_tag, options_)
1140 .Add(AbortChunk(
1141 /*filled_in_verification_tag=*/false,
1142 Parameters::Builder()
1143 .Add(ProtocolViolationCause("INIT-ACK malformed"))
1144 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001145 InternalClose(ErrorKind::kProtocolViolation,
1146 "InitAck chunk doesn't contain a cookie");
1147 return;
1148 }
1149 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1150 t1_init_->Stop();
1151
1152 tcb_ = std::make_unique<TransmissionControlBlock>(
1153 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
1154 send_queue_, connect_params_.verification_tag,
1155 connect_params_.initial_tsn, chunk->initiate_tag(), chunk->initial_tsn(),
Victor Boivieabf61882021-08-12 15:57:49 +02001156 chunk->a_rwnd(), MakeTieTag(callbacks_), packet_sender_,
1157 [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001158 RTC_DLOG(LS_VERBOSE) << log_prefix()
1159 << "Created peer TCB: " << tcb_->ToString();
1160
1161 SetState(State::kCookieEchoed, "INIT_ACK received");
1162
1163 // The connection isn't fully established just yet.
Victor Boiviec20f1562021-06-16 12:52:42 +02001164 tcb_->SetCookieEchoChunk(CookieEchoChunk(cookie->data()));
1165 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001166 t1_cookie_->Start();
1167}
1168
1169void DcSctpSocket::HandleCookieEcho(
1170 const CommonHeader& header,
1171 const SctpPacket::ChunkDescriptor& descriptor) {
1172 absl::optional<CookieEchoChunk> chunk =
1173 CookieEchoChunk::Parse(descriptor.data);
1174 if (!ValidateParseSuccess(chunk)) {
1175 return;
1176 }
1177
1178 absl::optional<StateCookie> cookie =
1179 StateCookie::Deserialize(chunk->cookie());
1180 if (!cookie.has_value()) {
1181 callbacks_.OnError(ErrorKind::kParseFailed, "Failed to parse state cookie");
1182 return;
1183 }
1184
1185 if (tcb_ != nullptr) {
1186 if (!HandleCookieEchoWithTCB(header, *cookie)) {
1187 return;
1188 }
1189 } else {
1190 if (header.verification_tag != connect_params_.verification_tag) {
1191 callbacks_.OnError(
1192 ErrorKind::kParseFailed,
1193 rtc::StringFormat(
1194 "Received CookieEcho with invalid verification tag: %08x, "
1195 "expected %08x",
1196 *header.verification_tag, *connect_params_.verification_tag));
1197 return;
1198 }
1199 }
1200
1201 // The init timer can be running on simultaneous connections.
1202 t1_init_->Stop();
1203 t1_cookie_->Stop();
1204 if (state_ != State::kEstablished) {
Victor Boiviec20f1562021-06-16 12:52:42 +02001205 if (tcb_ != nullptr) {
1206 tcb_->ClearCookieEchoChunk();
1207 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001208 SetState(State::kEstablished, "COOKIE_ECHO received");
1209 callbacks_.OnConnected();
1210 }
1211
1212 if (tcb_ == nullptr) {
1213 tcb_ = std::make_unique<TransmissionControlBlock>(
1214 timer_manager_, log_prefix_, options_, cookie->capabilities(),
1215 callbacks_, send_queue_, connect_params_.verification_tag,
1216 connect_params_.initial_tsn, cookie->initiate_tag(),
1217 cookie->initial_tsn(), cookie->a_rwnd(), MakeTieTag(callbacks_),
Victor Boivieabf61882021-08-12 15:57:49 +02001218 packet_sender_, [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001219 RTC_DLOG(LS_VERBOSE) << log_prefix()
1220 << "Created peer TCB: " << tcb_->ToString();
1221 }
1222
1223 SctpPacket::Builder b = tcb_->PacketBuilder();
1224 b.Add(CookieAckChunk());
1225
1226 // https://tools.ietf.org/html/rfc4960#section-5.1
1227 // "A COOKIE ACK chunk may be bundled with any pending DATA chunks (and/or
1228 // SACK chunks), but the COOKIE ACK chunk MUST be the first chunk in the
1229 // packet."
Victor Boivied3b186e2021-05-05 16:22:29 +02001230 tcb_->SendBufferedPackets(b, callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001231}
1232
1233bool DcSctpSocket::HandleCookieEchoWithTCB(const CommonHeader& header,
1234 const StateCookie& cookie) {
1235 RTC_DLOG(LS_VERBOSE) << log_prefix()
1236 << "Handling CookieEchoChunk with TCB. local_tag="
1237 << *tcb_->my_verification_tag()
1238 << ", peer_tag=" << *header.verification_tag
1239 << ", tcb_tag=" << *tcb_->peer_verification_tag()
1240 << ", cookie_tag=" << *cookie.initiate_tag()
1241 << ", local_tie_tag=" << *tcb_->tie_tag()
1242 << ", peer_tie_tag=" << *cookie.tie_tag();
1243 // https://tools.ietf.org/html/rfc4960#section-5.2.4
1244 // "Handle a COOKIE ECHO when a TCB Exists"
1245 if (header.verification_tag != tcb_->my_verification_tag() &&
1246 tcb_->peer_verification_tag() != cookie.initiate_tag() &&
1247 cookie.tie_tag() == tcb_->tie_tag()) {
1248 // "A) In this case, the peer may have restarted."
1249 if (state_ == State::kShutdownAckSent) {
1250 // "If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
1251 // that the peer has restarted ... it MUST NOT set up a new association
1252 // but instead resend the SHUTDOWN ACK and send an ERROR chunk with a
1253 // "Cookie Received While Shutting Down" error cause to its peer."
1254 SctpPacket::Builder b(cookie.initiate_tag(), options_);
1255 b.Add(ShutdownAckChunk());
1256 b.Add(ErrorChunk(Parameters::Builder()
1257 .Add(CookieReceivedWhileShuttingDownCause())
1258 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001259 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001260 callbacks_.OnError(ErrorKind::kWrongSequence,
1261 "Received COOKIE-ECHO while shutting down");
1262 return false;
1263 }
1264
1265 RTC_DLOG(LS_VERBOSE) << log_prefix()
1266 << "Received COOKIE-ECHO indicating a restarted peer";
1267
1268 // If a message was partly sent, and the peer restarted, resend it in
1269 // full by resetting the send queue.
1270 send_queue_.Reset();
1271 tcb_ = nullptr;
1272 callbacks_.OnConnectionRestarted();
1273 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1274 tcb_->peer_verification_tag() != cookie.initiate_tag()) {
1275 // TODO(boivie): Handle the peer_tag == 0?
1276 // "B) In this case, both sides may be attempting to start an
1277 // association at about the same time, but the peer endpoint started its
1278 // INIT after responding to the local endpoint's INIT."
1279 RTC_DLOG(LS_VERBOSE)
1280 << log_prefix()
1281 << "Received COOKIE-ECHO indicating simultaneous connections";
1282 tcb_ = nullptr;
1283 } else if (header.verification_tag != tcb_->my_verification_tag() &&
1284 tcb_->peer_verification_tag() == cookie.initiate_tag() &&
1285 cookie.tie_tag() == TieTag(0)) {
1286 // "C) In this case, the local endpoint's cookie has arrived late.
1287 // Before it arrived, the local endpoint sent an INIT and received an
1288 // INIT ACK and finally sent a COOKIE ECHO with the peer's same tag but
1289 // a new tag of its own. The cookie should be silently discarded. The
1290 // endpoint SHOULD NOT change states and should leave any timers
1291 // running."
1292 RTC_DLOG(LS_VERBOSE)
1293 << log_prefix()
1294 << "Received COOKIE-ECHO indicating a late COOKIE-ECHO. Discarding";
1295 return false;
1296 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1297 tcb_->peer_verification_tag() == cookie.initiate_tag()) {
1298 // "D) When both local and remote tags match, the endpoint should enter
1299 // the ESTABLISHED state, if it is in the COOKIE-ECHOED state. It
1300 // should stop any cookie timer that may be running and send a COOKIE
1301 // ACK."
1302 RTC_DLOG(LS_VERBOSE)
1303 << log_prefix()
1304 << "Received duplicate COOKIE-ECHO, probably because of peer not "
1305 "receiving COOKIE-ACK and retransmitting COOKIE-ECHO. Continuing.";
1306 }
1307 return true;
1308}
1309
1310void DcSctpSocket::HandleCookieAck(
1311 const CommonHeader& header,
1312 const SctpPacket::ChunkDescriptor& descriptor) {
1313 absl::optional<CookieAckChunk> chunk = CookieAckChunk::Parse(descriptor.data);
1314 if (!ValidateParseSuccess(chunk)) {
1315 return;
1316 }
1317
1318 if (state_ != State::kCookieEchoed) {
1319 // https://tools.ietf.org/html/rfc4960#section-5.2.5
1320 // "At any state other than COOKIE-ECHOED, an endpoint should silently
1321 // discard a received COOKIE ACK chunk."
1322 RTC_DLOG(LS_VERBOSE) << log_prefix()
1323 << "Received COOKIE_ACK not in COOKIE_ECHOED state";
1324 return;
1325 }
1326
1327 // RFC 4960, Errata ID: 4400
1328 t1_cookie_->Stop();
Victor Boiviec20f1562021-06-16 12:52:42 +02001329 tcb_->ClearCookieEchoChunk();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001330 SetState(State::kEstablished, "COOKIE_ACK received");
Victor Boivied3b186e2021-05-05 16:22:29 +02001331 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001332 callbacks_.OnConnected();
1333}
1334
1335void DcSctpSocket::DeliverReassembledMessages() {
1336 if (tcb_->reassembly_queue().HasMessages()) {
1337 for (auto& message : tcb_->reassembly_queue().FlushMessages()) {
Victor Boivied4716ea2021-08-09 12:26:32 +02001338 ++metrics_.rx_messages_count;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001339 callbacks_.OnMessageReceived(std::move(message));
1340 }
1341 }
1342}
1343
1344void DcSctpSocket::HandleSack(const CommonHeader& header,
1345 const SctpPacket::ChunkDescriptor& descriptor) {
1346 absl::optional<SackChunk> chunk = SackChunk::Parse(descriptor.data);
1347
1348 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
Victor Boivied3b186e2021-05-05 16:22:29 +02001349 TimeMs now = callbacks_.TimeMillis();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001350 SackChunk sack = ChunkValidators::Clean(*std::move(chunk));
1351
Victor Boivied3b186e2021-05-05 16:22:29 +02001352 if (tcb_->retransmission_queue().HandleSack(now, sack)) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001353 MaybeSendShutdownOrAck();
1354 // Receiving an ACK will decrease outstanding bytes (maybe now below
1355 // cwnd?) or indicate packet loss that may result in sending FORWARD-TSN.
Victor Boivied3b186e2021-05-05 16:22:29 +02001356 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001357 } else {
1358 RTC_DLOG(LS_VERBOSE) << log_prefix()
1359 << "Dropping out-of-order SACK with TSN "
1360 << *sack.cumulative_tsn_ack();
1361 }
1362 }
1363}
1364
1365void DcSctpSocket::HandleHeartbeatRequest(
1366 const CommonHeader& header,
1367 const SctpPacket::ChunkDescriptor& descriptor) {
1368 absl::optional<HeartbeatRequestChunk> chunk =
1369 HeartbeatRequestChunk::Parse(descriptor.data);
1370
1371 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1372 tcb_->heartbeat_handler().HandleHeartbeatRequest(*std::move(chunk));
1373 }
1374}
1375
1376void DcSctpSocket::HandleHeartbeatAck(
1377 const CommonHeader& header,
1378 const SctpPacket::ChunkDescriptor& descriptor) {
1379 absl::optional<HeartbeatAckChunk> chunk =
1380 HeartbeatAckChunk::Parse(descriptor.data);
1381
1382 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1383 tcb_->heartbeat_handler().HandleHeartbeatAck(*std::move(chunk));
1384 }
1385}
1386
1387void DcSctpSocket::HandleAbort(const CommonHeader& header,
1388 const SctpPacket::ChunkDescriptor& descriptor) {
1389 absl::optional<AbortChunk> chunk = AbortChunk::Parse(descriptor.data);
1390 if (ValidateParseSuccess(chunk)) {
1391 std::string error_string = ErrorCausesToString(chunk->error_causes());
1392 if (tcb_ == nullptr) {
1393 // https://tools.ietf.org/html/rfc4960#section-3.3.7
1394 // "If an endpoint receives an ABORT with a format error or no TCB is
1395 // found, it MUST silently discard it."
1396 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ABORT (" << error_string
1397 << ") on a connection with no TCB. Ignoring";
1398 return;
1399 }
1400
1401 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ABORT (" << error_string
1402 << ") - closing connection.";
1403 InternalClose(ErrorKind::kPeerReported, error_string);
1404 }
1405}
1406
1407void DcSctpSocket::HandleError(const CommonHeader& header,
1408 const SctpPacket::ChunkDescriptor& descriptor) {
1409 absl::optional<ErrorChunk> chunk = ErrorChunk::Parse(descriptor.data);
1410 if (ValidateParseSuccess(chunk)) {
1411 std::string error_string = ErrorCausesToString(chunk->error_causes());
1412 if (tcb_ == nullptr) {
1413 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ERROR (" << error_string
1414 << ") on a connection with no TCB. Ignoring";
1415 return;
1416 }
1417
1418 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ERROR: " << error_string;
1419 callbacks_.OnError(ErrorKind::kPeerReported,
1420 "Peer reported error: " + error_string);
1421 }
1422}
1423
1424void DcSctpSocket::HandleReconfig(
1425 const CommonHeader& header,
1426 const SctpPacket::ChunkDescriptor& descriptor) {
1427 absl::optional<ReConfigChunk> chunk = ReConfigChunk::Parse(descriptor.data);
1428 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1429 tcb_->stream_reset_handler().HandleReConfig(*std::move(chunk));
1430 }
1431}
1432
1433void DcSctpSocket::HandleShutdown(
1434 const CommonHeader& header,
1435 const SctpPacket::ChunkDescriptor& descriptor) {
1436 if (!ValidateParseSuccess(ShutdownChunk::Parse(descriptor.data))) {
1437 return;
1438 }
1439
1440 if (state_ == State::kClosed) {
1441 return;
1442 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1443 // https://tools.ietf.org/html/rfc4960#section-9.2
1444 // "If a SHUTDOWN is received in the COOKIE-WAIT or COOKIE ECHOED state,
1445 // the SHUTDOWN chunk SHOULD be silently discarded."
1446 } else if (state_ == State::kShutdownSent) {
1447 // https://tools.ietf.org/html/rfc4960#section-9.2
1448 // "If an endpoint is in the SHUTDOWN-SENT state and receives a
1449 // SHUTDOWN chunk from its peer, the endpoint shall respond immediately
1450 // with a SHUTDOWN ACK to its peer, and move into the SHUTDOWN-ACK-SENT
1451 // state restarting its T2-shutdown timer."
1452 SendShutdownAck();
1453 SetState(State::kShutdownAckSent, "SHUTDOWN received");
Victor Boivie50a0b122021-05-06 21:07:49 +02001454 } else if (state_ == State::kShutdownAckSent) {
1455 // TODO(webrtc:12739): This condition should be removed and handled by the
1456 // next (state_ != State::kShutdownReceived).
1457 return;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001458 } else if (state_ != State::kShutdownReceived) {
1459 RTC_DLOG(LS_VERBOSE) << log_prefix()
1460 << "Received SHUTDOWN - shutting down the socket";
1461 // https://tools.ietf.org/html/rfc4960#section-9.2
1462 // "Upon reception of the SHUTDOWN, the peer endpoint shall enter the
1463 // SHUTDOWN-RECEIVED state, stop accepting new data from its SCTP user,
1464 // and verify, by checking the Cumulative TSN Ack field of the chunk, that
1465 // all its outstanding DATA chunks have been received by the SHUTDOWN
1466 // sender."
1467 SetState(State::kShutdownReceived, "SHUTDOWN received");
1468 MaybeSendShutdownOrAck();
1469 }
1470}
1471
1472void DcSctpSocket::HandleShutdownAck(
1473 const CommonHeader& header,
1474 const SctpPacket::ChunkDescriptor& descriptor) {
1475 if (!ValidateParseSuccess(ShutdownAckChunk::Parse(descriptor.data))) {
1476 return;
1477 }
1478
1479 if (state_ == State::kShutdownSent || state_ == State::kShutdownAckSent) {
1480 // https://tools.ietf.org/html/rfc4960#section-9.2
1481 // "Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall stop
1482 // the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its peer, and
1483 // remove all record of the association."
1484
1485 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives a
1486 // SHUTDOWN ACK, it shall stop the T2-shutdown timer, send a SHUTDOWN
1487 // COMPLETE chunk to its peer, and remove all record of the association."
1488
1489 SctpPacket::Builder b = tcb_->PacketBuilder();
1490 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/false));
Victor Boivieabf61882021-08-12 15:57:49 +02001491 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001492 InternalClose(ErrorKind::kNoError, "");
1493 } else {
1494 // https://tools.ietf.org/html/rfc4960#section-8.5.1
1495 // "If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state
1496 // the procedures in Section 8.4 SHOULD be followed; in other words, it
1497 // should be treated as an Out Of The Blue packet."
1498
1499 // https://tools.ietf.org/html/rfc4960#section-8.4
1500 // "If the packet contains a SHUTDOWN ACK chunk, the receiver
1501 // should respond to the sender of the OOTB packet with a SHUTDOWN
1502 // COMPLETE. When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
1503 // packet must fill in the Verification Tag field of the outbound packet
1504 // with the Verification Tag received in the SHUTDOWN ACK and set the T
1505 // bit in the Chunk Flags to indicate that the Verification Tag is
1506 // reflected."
1507
1508 SctpPacket::Builder b(header.verification_tag, options_);
1509 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/true));
Victor Boivieabf61882021-08-12 15:57:49 +02001510 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001511 }
1512}
1513
1514void DcSctpSocket::HandleShutdownComplete(
1515 const CommonHeader& header,
1516 const SctpPacket::ChunkDescriptor& descriptor) {
1517 if (!ValidateParseSuccess(ShutdownCompleteChunk::Parse(descriptor.data))) {
1518 return;
1519 }
1520
1521 if (state_ == State::kShutdownAckSent) {
1522 // https://tools.ietf.org/html/rfc4960#section-9.2
1523 // "Upon reception of the SHUTDOWN COMPLETE chunk, the endpoint will
1524 // verify that it is in the SHUTDOWN-ACK-SENT state; if it is not, the
1525 // chunk should be discarded. If the endpoint is in the SHUTDOWN-ACK-SENT
1526 // state, the endpoint should stop the T2-shutdown timer and remove all
1527 // knowledge of the association (and thus the association enters the
1528 // CLOSED state)."
1529 InternalClose(ErrorKind::kNoError, "");
1530 }
1531}
1532
1533void DcSctpSocket::HandleForwardTsn(
1534 const CommonHeader& header,
1535 const SctpPacket::ChunkDescriptor& descriptor) {
1536 absl::optional<ForwardTsnChunk> chunk =
1537 ForwardTsnChunk::Parse(descriptor.data);
1538 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1539 HandleForwardTsnCommon(*chunk);
1540 }
1541}
1542
1543void DcSctpSocket::HandleIForwardTsn(
1544 const CommonHeader& header,
1545 const SctpPacket::ChunkDescriptor& descriptor) {
1546 absl::optional<IForwardTsnChunk> chunk =
1547 IForwardTsnChunk::Parse(descriptor.data);
1548 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1549 HandleForwardTsnCommon(*chunk);
1550 }
1551}
1552
1553void DcSctpSocket::HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk) {
1554 if (!tcb_->capabilities().partial_reliability) {
1555 SctpPacket::Builder b = tcb_->PacketBuilder();
1556 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
1557 Parameters::Builder()
1558 .Add(ProtocolViolationCause(
1559 "I-FORWARD-TSN received, but not indicated "
1560 "during connection establishment"))
1561 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001562 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001563
1564 callbacks_.OnError(ErrorKind::kProtocolViolation,
1565 "Received a FORWARD_TSN without announced peer support");
1566 return;
1567 }
1568 tcb_->data_tracker().HandleForwardTsn(chunk.new_cumulative_tsn());
1569 tcb_->reassembly_queue().Handle(chunk);
1570 // A forward TSN - for ordered streams - may allow messages to be
1571 // delivered.
1572 DeliverReassembledMessages();
1573
1574 // Processing a FORWARD_TSN might result in sending a SACK.
1575 tcb_->MaybeSendSack();
1576}
1577
1578void DcSctpSocket::MaybeSendShutdownOrAck() {
1579 if (tcb_->retransmission_queue().outstanding_bytes() != 0) {
1580 return;
1581 }
1582
1583 if (state_ == State::kShutdownPending) {
1584 // https://tools.ietf.org/html/rfc4960#section-9.2
1585 // "Once all its outstanding data has been acknowledged, the endpoint
1586 // shall send a SHUTDOWN chunk to its peer including in the Cumulative TSN
1587 // Ack field the last sequential TSN it has received from the peer. It
1588 // shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT
1589 // state.""
1590
1591 SendShutdown();
1592 t2_shutdown_->set_duration(tcb_->current_rto());
1593 t2_shutdown_->Start();
1594 SetState(State::kShutdownSent, "No more outstanding data");
1595 } else if (state_ == State::kShutdownReceived) {
1596 // https://tools.ietf.org/html/rfc4960#section-9.2
1597 // "If the receiver of the SHUTDOWN has no more outstanding DATA
1598 // chunks, the SHUTDOWN receiver MUST send a SHUTDOWN ACK and start a
1599 // T2-shutdown timer of its own, entering the SHUTDOWN-ACK-SENT state. If
1600 // the timer expires, the endpoint must resend the SHUTDOWN ACK."
1601
1602 SendShutdownAck();
1603 SetState(State::kShutdownAckSent, "No more outstanding data");
1604 }
1605}
1606
1607void DcSctpSocket::SendShutdown() {
1608 SctpPacket::Builder b = tcb_->PacketBuilder();
1609 b.Add(ShutdownChunk(tcb_->data_tracker().last_cumulative_acked_tsn()));
Victor Boivieabf61882021-08-12 15:57:49 +02001610 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001611}
1612
1613void DcSctpSocket::SendShutdownAck() {
Victor Boivieabf61882021-08-12 15:57:49 +02001614 packet_sender_.Send(tcb_->PacketBuilder().Add(ShutdownAckChunk()));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001615 t2_shutdown_->set_duration(tcb_->current_rto());
1616 t2_shutdown_->Start();
1617}
1618
Sergey Sukhanov43972812021-09-17 15:32:48 +02001619HandoverReadinessStatus DcSctpSocket::GetHandoverReadiness() const {
1620 HandoverReadinessStatus status;
1621 if (state_ != State::kClosed && state_ != State::kEstablished) {
1622 status.Add(HandoverUnreadinessReason::kWrongConnectionState);
1623 }
Sergey Sukhanov72435322021-09-21 13:31:09 +02001624 status.Add(send_queue_.GetHandoverReadiness());
Sergey Sukhanov43972812021-09-17 15:32:48 +02001625 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);
Sergey Sukhanov72435322021-09-21 13:31:09 +02001644 send_queue_.AddHandoverState(state);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001645 InternalClose(ErrorKind::kNoError, "handover");
1646 callbacks_.TriggerDeferred();
1647 }
1648
1649 return std::move(state);
1650}
1651
Victor Boivieb6580cc2021-04-08 09:56:59 +02001652} // namespace dcsctp