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