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