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