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