blob: a39ec5ce88b116cf1809d126869c798a1ab55da0 [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()
778 << "/" << t1_init_->options().max_restarts;
779 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()
799 << "/" << t1_cookie_->options().max_restarts;
800
801 RTC_DCHECK(state_ == State::kCookieEchoed);
802
803 if (t1_cookie_->is_running()) {
Victor Boiviec20f1562021-06-16 12:52:42 +0200804 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200805 } else {
806 InternalClose(ErrorKind::kTooManyRetries, "No COOKIE_ACK received");
807 }
808
809 RTC_DCHECK(IsConsistent());
810 return absl::nullopt;
811}
812
813absl::optional<DurationMs> DcSctpSocket::OnShutdownTimerExpiry() {
814 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t2_shutdown_->name()
815 << " has expired: " << t2_shutdown_->expiration_count()
816 << "/" << t2_shutdown_->options().max_restarts;
817
Victor Boivie914925f2021-05-07 11:22:50 +0200818 if (!t2_shutdown_->is_running()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +0200819 // https://tools.ietf.org/html/rfc4960#section-9.2
820 // "An endpoint should limit the number of retransmissions of the SHUTDOWN
821 // chunk to the protocol parameter 'Association.Max.Retrans'. If this
822 // threshold is exceeded, the endpoint should destroy the TCB..."
823
Victor Boivieabf61882021-08-12 15:57:49 +0200824 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200825 AbortChunk(true, Parameters::Builder()
826 .Add(UserInitiatedAbortCause(
827 "Too many retransmissions of SHUTDOWN"))
828 .Build())));
829
830 InternalClose(ErrorKind::kTooManyRetries, "No SHUTDOWN_ACK received");
Victor Boivie914925f2021-05-07 11:22:50 +0200831 RTC_DCHECK(IsConsistent());
832 return absl::nullopt;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200833 }
Victor Boivie914925f2021-05-07 11:22:50 +0200834
835 // https://tools.ietf.org/html/rfc4960#section-9.2
836 // "If the timer expires, the endpoint must resend the SHUTDOWN with the
837 // updated last sequential TSN received from its peer."
838 SendShutdown();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200839 RTC_DCHECK(IsConsistent());
840 return tcb_->current_rto();
841}
842
Victor Boivieabf61882021-08-12 15:57:49 +0200843void DcSctpSocket::OnSentPacket(rtc::ArrayView<const uint8_t> packet,
844 SendPacketStatus status) {
845 // The packet observer is invoked even if the packet was failed to be sent, to
846 // indicate an attempt was made.
Victor Boivieb6580cc2021-04-08 09:56:59 +0200847 if (packet_observer_ != nullptr) {
Victor Boivieabf61882021-08-12 15:57:49 +0200848 packet_observer_->OnSentPacket(callbacks_.TimeMillis(), packet);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200849 }
Victor Boivieabf61882021-08-12 15:57:49 +0200850
851 if (status == SendPacketStatus::kSuccess) {
852 if (RTC_DLOG_IS_ON) {
853 DebugPrintOutgoing(packet);
854 }
855
856 // The heartbeat interval timer is restarted for every sent packet, to
857 // fire when the outgoing channel is inactive.
858 if (tcb_ != nullptr) {
859 tcb_->heartbeat_handler().RestartTimer();
860 }
861
862 ++metrics_.tx_packets_count;
863 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200864}
865
866bool DcSctpSocket::ValidateHasTCB() {
867 if (tcb_ != nullptr) {
868 return true;
869 }
870
871 callbacks_.OnError(
872 ErrorKind::kNotConnected,
873 "Received unexpected commands on socket that is not connected");
874 return false;
875}
876
877void DcSctpSocket::ReportFailedToParseChunk(int chunk_type) {
878 rtc::StringBuilder sb;
879 sb << "Failed to parse chunk of type: " << chunk_type;
880 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
881}
882
883void DcSctpSocket::HandleData(const CommonHeader& header,
884 const SctpPacket::ChunkDescriptor& descriptor) {
885 absl::optional<DataChunk> chunk = DataChunk::Parse(descriptor.data);
886 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
887 HandleDataCommon(*chunk);
888 }
889}
890
891void DcSctpSocket::HandleIData(const CommonHeader& header,
892 const SctpPacket::ChunkDescriptor& descriptor) {
893 absl::optional<IDataChunk> chunk = IDataChunk::Parse(descriptor.data);
894 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
895 HandleDataCommon(*chunk);
896 }
897}
898
899void DcSctpSocket::HandleDataCommon(AnyDataChunk& chunk) {
900 TSN tsn = chunk.tsn();
901 AnyDataChunk::ImmediateAckFlag immediate_ack = chunk.options().immediate_ack;
902 Data data = std::move(chunk).extract();
903
904 if (data.payload.empty()) {
905 // Empty DATA chunks are illegal.
Victor Boivieabf61882021-08-12 15:57:49 +0200906 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200907 ErrorChunk(Parameters::Builder().Add(NoUserDataCause(tsn)).Build())));
908 callbacks_.OnError(ErrorKind::kProtocolViolation,
909 "Received DATA chunk with no user data");
910 return;
911 }
912
913 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Handle DATA, queue_size="
914 << tcb_->reassembly_queue().queued_bytes()
915 << ", water_mark="
916 << tcb_->reassembly_queue().watermark_bytes()
917 << ", full=" << tcb_->reassembly_queue().is_full()
918 << ", above="
919 << tcb_->reassembly_queue().is_above_watermark();
920
921 if (tcb_->reassembly_queue().is_full()) {
922 // If the reassembly queue is full, there is nothing that can be done. The
923 // specification only allows dropping gap-ack-blocks, and that's not
924 // likely to help as the socket has been trying to fill gaps since the
925 // watermark was reached.
Victor Boivieabf61882021-08-12 15:57:49 +0200926 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200927 true, Parameters::Builder().Add(OutOfResourceErrorCause()).Build())));
928 InternalClose(ErrorKind::kResourceExhaustion,
929 "Reassembly Queue is exhausted");
930 return;
931 }
932
933 if (tcb_->reassembly_queue().is_above_watermark()) {
934 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Is above high watermark";
935 // If the reassembly queue is above its high watermark, only accept data
936 // chunks that increase its cumulative ack tsn in an attempt to fill gaps
937 // to deliver messages.
938 if (!tcb_->data_tracker().will_increase_cum_ack_tsn(tsn)) {
939 RTC_DLOG(LS_VERBOSE) << log_prefix()
940 << "Rejected data because of exceeding watermark";
941 tcb_->data_tracker().ForceImmediateSack();
942 return;
943 }
944 }
945
946 if (!tcb_->data_tracker().IsTSNValid(tsn)) {
947 RTC_DLOG(LS_VERBOSE) << log_prefix()
948 << "Rejected data because of failing TSN validity";
949 return;
950 }
951
952 tcb_->data_tracker().Observe(tsn, immediate_ack);
953 tcb_->reassembly_queue().MaybeResetStreamsDeferred(
954 tcb_->data_tracker().last_cumulative_acked_tsn());
955 tcb_->reassembly_queue().Add(tsn, std::move(data));
956 DeliverReassembledMessages();
957}
958
959void DcSctpSocket::HandleInit(const CommonHeader& header,
960 const SctpPacket::ChunkDescriptor& descriptor) {
961 absl::optional<InitChunk> chunk = InitChunk::Parse(descriptor.data);
962 if (!ValidateParseSuccess(chunk)) {
963 return;
964 }
965
966 if (chunk->initiate_tag() == VerificationTag(0) ||
967 chunk->nbr_outbound_streams() == 0 || chunk->nbr_inbound_streams() == 0) {
968 // https://tools.ietf.org/html/rfc4960#section-3.3.2
969 // "If the value of the Initiate Tag in a received INIT chunk is found
970 // to be 0, the receiver MUST treat it as an error and close the
971 // association by transmitting an ABORT."
972
973 // "A receiver of an INIT with the OS value set to 0 SHOULD abort the
974 // association."
975
976 // "A receiver of an INIT with the MIS value of 0 SHOULD abort the
977 // association."
978
Victor Boivieabf61882021-08-12 15:57:49 +0200979 packet_sender_.Send(
980 SctpPacket::Builder(VerificationTag(0), options_)
981 .Add(AbortChunk(
982 /*filled_in_verification_tag=*/false,
983 Parameters::Builder()
984 .Add(ProtocolViolationCause("INIT malformed"))
985 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +0200986 InternalClose(ErrorKind::kProtocolViolation, "Received invalid INIT");
987 return;
988 }
989
990 if (state_ == State::kShutdownAckSent) {
991 // https://tools.ietf.org/html/rfc4960#section-9.2
992 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives an
993 // INIT chunk (e.g., if the SHUTDOWN COMPLETE was lost) with source and
994 // destination transport addresses (either in the IP addresses or in the
995 // INIT chunk) that belong to this association, it should discard the INIT
996 // chunk and retransmit the SHUTDOWN ACK chunk."
997 RTC_DLOG(LS_VERBOSE) << log_prefix()
998 << "Received Init indicating lost ShutdownComplete";
999 SendShutdownAck();
1000 return;
1001 }
1002
1003 TieTag tie_tag(0);
1004 if (state_ == State::kClosed) {
1005 RTC_DLOG(LS_VERBOSE) << log_prefix()
1006 << "Received Init in closed state (normal)";
1007
1008 MakeConnectionParameters();
1009 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1010 // https://tools.ietf.org/html/rfc4960#section-5.2.1
1011 // "This usually indicates an initialization collision, i.e., each
1012 // endpoint is attempting, at about the same time, to establish an
1013 // association with the other endpoint. Upon receipt of an INIT in the
1014 // COOKIE-WAIT state, an endpoint MUST respond with an INIT ACK using the
1015 // same parameters it sent in its original INIT chunk (including its
1016 // Initiate Tag, unchanged). When responding, the endpoint MUST send the
1017 // INIT ACK back to the same address that the original INIT (sent by this
1018 // endpoint) was sent."
1019 RTC_DLOG(LS_VERBOSE) << log_prefix()
1020 << "Received Init indicating simultaneous connections";
1021 } else {
1022 RTC_DCHECK(tcb_ != nullptr);
1023 // https://tools.ietf.org/html/rfc4960#section-5.2.2
1024 // "The outbound SCTP packet containing this INIT ACK MUST carry a
1025 // Verification Tag value equal to the Initiate Tag found in the
1026 // unexpected INIT. And the INIT ACK MUST contain a new Initiate Tag
1027 // (randomly generated; see Section 5.3.1). Other parameters for the
1028 // endpoint SHOULD be copied from the existing parameters of the
1029 // association (e.g., number of outbound streams) into the INIT ACK and
1030 // cookie."
1031 RTC_DLOG(LS_VERBOSE) << log_prefix()
1032 << "Received Init indicating restarted connection";
1033 // Create a new verification tag - different from the previous one.
1034 for (int tries = 0; tries < 10; ++tries) {
1035 connect_params_.verification_tag = VerificationTag(
1036 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
1037 if (connect_params_.verification_tag != tcb_->my_verification_tag()) {
1038 break;
1039 }
1040 }
1041
1042 // Make the initial TSN make a large jump, so that there is no overlap
1043 // with the old and new association.
1044 connect_params_.initial_tsn =
1045 TSN(*tcb_->retransmission_queue().next_tsn() + 1000000);
1046 tie_tag = tcb_->tie_tag();
1047 }
1048
1049 RTC_DLOG(LS_VERBOSE)
1050 << log_prefix()
1051 << rtc::StringFormat(
1052 "Proceeding with connection. my_verification_tag=%08x, "
1053 "my_initial_tsn=%u, peer_verification_tag=%08x, "
1054 "peer_initial_tsn=%u",
1055 *connect_params_.verification_tag, *connect_params_.initial_tsn,
1056 *chunk->initiate_tag(), *chunk->initial_tsn());
1057
1058 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1059
1060 SctpPacket::Builder b(chunk->initiate_tag(), options_);
1061 Parameters::Builder params_builder =
1062 Parameters::Builder().Add(StateCookieParameter(
1063 StateCookie(chunk->initiate_tag(), chunk->initial_tsn(),
1064 chunk->a_rwnd(), tie_tag, capabilities)
1065 .Serialize()));
1066 AddCapabilityParameters(options_, params_builder);
1067
1068 InitAckChunk init_ack(/*initiate_tag=*/connect_params_.verification_tag,
1069 options_.max_receiver_window_buffer_size,
1070 options_.announced_maximum_outgoing_streams,
1071 options_.announced_maximum_incoming_streams,
1072 connect_params_.initial_tsn, params_builder.Build());
1073 b.Add(init_ack);
Victor Boivieabf61882021-08-12 15:57:49 +02001074 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001075}
1076
Victor Boivieb6580cc2021-04-08 09:56:59 +02001077void DcSctpSocket::HandleInitAck(
1078 const CommonHeader& header,
1079 const SctpPacket::ChunkDescriptor& descriptor) {
1080 absl::optional<InitAckChunk> chunk = InitAckChunk::Parse(descriptor.data);
1081 if (!ValidateParseSuccess(chunk)) {
1082 return;
1083 }
1084
1085 if (state_ != State::kCookieWait) {
1086 // https://tools.ietf.org/html/rfc4960#section-5.2.3
1087 // "If an INIT ACK is received by an endpoint in any state other than
1088 // the COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk."
1089 RTC_DLOG(LS_VERBOSE) << log_prefix()
1090 << "Received INIT_ACK in unexpected state";
1091 return;
1092 }
1093
1094 auto cookie = chunk->parameters().get<StateCookieParameter>();
1095 if (!cookie.has_value()) {
Victor Boivieabf61882021-08-12 15:57:49 +02001096 packet_sender_.Send(
1097 SctpPacket::Builder(connect_params_.verification_tag, options_)
1098 .Add(AbortChunk(
1099 /*filled_in_verification_tag=*/false,
1100 Parameters::Builder()
1101 .Add(ProtocolViolationCause("INIT-ACK malformed"))
1102 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001103 InternalClose(ErrorKind::kProtocolViolation,
1104 "InitAck chunk doesn't contain a cookie");
1105 return;
1106 }
1107 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1108 t1_init_->Stop();
1109
1110 tcb_ = std::make_unique<TransmissionControlBlock>(
1111 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
1112 send_queue_, connect_params_.verification_tag,
1113 connect_params_.initial_tsn, chunk->initiate_tag(), chunk->initial_tsn(),
Victor Boivieabf61882021-08-12 15:57:49 +02001114 chunk->a_rwnd(), MakeTieTag(callbacks_), packet_sender_,
1115 [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001116 RTC_DLOG(LS_VERBOSE) << log_prefix()
1117 << "Created peer TCB: " << tcb_->ToString();
1118
1119 SetState(State::kCookieEchoed, "INIT_ACK received");
1120
1121 // The connection isn't fully established just yet.
Victor Boiviec20f1562021-06-16 12:52:42 +02001122 tcb_->SetCookieEchoChunk(CookieEchoChunk(cookie->data()));
1123 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001124 t1_cookie_->Start();
1125}
1126
1127void DcSctpSocket::HandleCookieEcho(
1128 const CommonHeader& header,
1129 const SctpPacket::ChunkDescriptor& descriptor) {
1130 absl::optional<CookieEchoChunk> chunk =
1131 CookieEchoChunk::Parse(descriptor.data);
1132 if (!ValidateParseSuccess(chunk)) {
1133 return;
1134 }
1135
1136 absl::optional<StateCookie> cookie =
1137 StateCookie::Deserialize(chunk->cookie());
1138 if (!cookie.has_value()) {
1139 callbacks_.OnError(ErrorKind::kParseFailed, "Failed to parse state cookie");
1140 return;
1141 }
1142
1143 if (tcb_ != nullptr) {
1144 if (!HandleCookieEchoWithTCB(header, *cookie)) {
1145 return;
1146 }
1147 } else {
1148 if (header.verification_tag != connect_params_.verification_tag) {
1149 callbacks_.OnError(
1150 ErrorKind::kParseFailed,
1151 rtc::StringFormat(
1152 "Received CookieEcho with invalid verification tag: %08x, "
1153 "expected %08x",
1154 *header.verification_tag, *connect_params_.verification_tag));
1155 return;
1156 }
1157 }
1158
1159 // The init timer can be running on simultaneous connections.
1160 t1_init_->Stop();
1161 t1_cookie_->Stop();
1162 if (state_ != State::kEstablished) {
Victor Boiviec20f1562021-06-16 12:52:42 +02001163 if (tcb_ != nullptr) {
1164 tcb_->ClearCookieEchoChunk();
1165 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001166 SetState(State::kEstablished, "COOKIE_ECHO received");
1167 callbacks_.OnConnected();
1168 }
1169
1170 if (tcb_ == nullptr) {
1171 tcb_ = std::make_unique<TransmissionControlBlock>(
1172 timer_manager_, log_prefix_, options_, cookie->capabilities(),
1173 callbacks_, send_queue_, connect_params_.verification_tag,
1174 connect_params_.initial_tsn, cookie->initiate_tag(),
1175 cookie->initial_tsn(), cookie->a_rwnd(), MakeTieTag(callbacks_),
Victor Boivieabf61882021-08-12 15:57:49 +02001176 packet_sender_, [this]() { return state_ == State::kEstablished; });
Victor Boivieb6580cc2021-04-08 09:56:59 +02001177 RTC_DLOG(LS_VERBOSE) << log_prefix()
1178 << "Created peer TCB: " << tcb_->ToString();
1179 }
1180
1181 SctpPacket::Builder b = tcb_->PacketBuilder();
1182 b.Add(CookieAckChunk());
1183
1184 // https://tools.ietf.org/html/rfc4960#section-5.1
1185 // "A COOKIE ACK chunk may be bundled with any pending DATA chunks (and/or
1186 // SACK chunks), but the COOKIE ACK chunk MUST be the first chunk in the
1187 // packet."
Victor Boivied3b186e2021-05-05 16:22:29 +02001188 tcb_->SendBufferedPackets(b, callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001189}
1190
1191bool DcSctpSocket::HandleCookieEchoWithTCB(const CommonHeader& header,
1192 const StateCookie& cookie) {
1193 RTC_DLOG(LS_VERBOSE) << log_prefix()
1194 << "Handling CookieEchoChunk with TCB. local_tag="
1195 << *tcb_->my_verification_tag()
1196 << ", peer_tag=" << *header.verification_tag
1197 << ", tcb_tag=" << *tcb_->peer_verification_tag()
1198 << ", cookie_tag=" << *cookie.initiate_tag()
1199 << ", local_tie_tag=" << *tcb_->tie_tag()
1200 << ", peer_tie_tag=" << *cookie.tie_tag();
1201 // https://tools.ietf.org/html/rfc4960#section-5.2.4
1202 // "Handle a COOKIE ECHO when a TCB Exists"
1203 if (header.verification_tag != tcb_->my_verification_tag() &&
1204 tcb_->peer_verification_tag() != cookie.initiate_tag() &&
1205 cookie.tie_tag() == tcb_->tie_tag()) {
1206 // "A) In this case, the peer may have restarted."
1207 if (state_ == State::kShutdownAckSent) {
1208 // "If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
1209 // that the peer has restarted ... it MUST NOT set up a new association
1210 // but instead resend the SHUTDOWN ACK and send an ERROR chunk with a
1211 // "Cookie Received While Shutting Down" error cause to its peer."
1212 SctpPacket::Builder b(cookie.initiate_tag(), options_);
1213 b.Add(ShutdownAckChunk());
1214 b.Add(ErrorChunk(Parameters::Builder()
1215 .Add(CookieReceivedWhileShuttingDownCause())
1216 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001217 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001218 callbacks_.OnError(ErrorKind::kWrongSequence,
1219 "Received COOKIE-ECHO while shutting down");
1220 return false;
1221 }
1222
1223 RTC_DLOG(LS_VERBOSE) << log_prefix()
1224 << "Received COOKIE-ECHO indicating a restarted peer";
1225
1226 // If a message was partly sent, and the peer restarted, resend it in
1227 // full by resetting the send queue.
1228 send_queue_.Reset();
1229 tcb_ = nullptr;
1230 callbacks_.OnConnectionRestarted();
1231 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1232 tcb_->peer_verification_tag() != cookie.initiate_tag()) {
1233 // TODO(boivie): Handle the peer_tag == 0?
1234 // "B) In this case, both sides may be attempting to start an
1235 // association at about the same time, but the peer endpoint started its
1236 // INIT after responding to the local endpoint's INIT."
1237 RTC_DLOG(LS_VERBOSE)
1238 << log_prefix()
1239 << "Received COOKIE-ECHO indicating simultaneous connections";
1240 tcb_ = nullptr;
1241 } else if (header.verification_tag != tcb_->my_verification_tag() &&
1242 tcb_->peer_verification_tag() == cookie.initiate_tag() &&
1243 cookie.tie_tag() == TieTag(0)) {
1244 // "C) In this case, the local endpoint's cookie has arrived late.
1245 // Before it arrived, the local endpoint sent an INIT and received an
1246 // INIT ACK and finally sent a COOKIE ECHO with the peer's same tag but
1247 // a new tag of its own. The cookie should be silently discarded. The
1248 // endpoint SHOULD NOT change states and should leave any timers
1249 // running."
1250 RTC_DLOG(LS_VERBOSE)
1251 << log_prefix()
1252 << "Received COOKIE-ECHO indicating a late COOKIE-ECHO. Discarding";
1253 return false;
1254 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1255 tcb_->peer_verification_tag() == cookie.initiate_tag()) {
1256 // "D) When both local and remote tags match, the endpoint should enter
1257 // the ESTABLISHED state, if it is in the COOKIE-ECHOED state. It
1258 // should stop any cookie timer that may be running and send a COOKIE
1259 // ACK."
1260 RTC_DLOG(LS_VERBOSE)
1261 << log_prefix()
1262 << "Received duplicate COOKIE-ECHO, probably because of peer not "
1263 "receiving COOKIE-ACK and retransmitting COOKIE-ECHO. Continuing.";
1264 }
1265 return true;
1266}
1267
1268void DcSctpSocket::HandleCookieAck(
1269 const CommonHeader& header,
1270 const SctpPacket::ChunkDescriptor& descriptor) {
1271 absl::optional<CookieAckChunk> chunk = CookieAckChunk::Parse(descriptor.data);
1272 if (!ValidateParseSuccess(chunk)) {
1273 return;
1274 }
1275
1276 if (state_ != State::kCookieEchoed) {
1277 // https://tools.ietf.org/html/rfc4960#section-5.2.5
1278 // "At any state other than COOKIE-ECHOED, an endpoint should silently
1279 // discard a received COOKIE ACK chunk."
1280 RTC_DLOG(LS_VERBOSE) << log_prefix()
1281 << "Received COOKIE_ACK not in COOKIE_ECHOED state";
1282 return;
1283 }
1284
1285 // RFC 4960, Errata ID: 4400
1286 t1_cookie_->Stop();
Victor Boiviec20f1562021-06-16 12:52:42 +02001287 tcb_->ClearCookieEchoChunk();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001288 SetState(State::kEstablished, "COOKIE_ACK received");
Victor Boivied3b186e2021-05-05 16:22:29 +02001289 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001290 callbacks_.OnConnected();
1291}
1292
1293void DcSctpSocket::DeliverReassembledMessages() {
1294 if (tcb_->reassembly_queue().HasMessages()) {
1295 for (auto& message : tcb_->reassembly_queue().FlushMessages()) {
Victor Boivied4716ea2021-08-09 12:26:32 +02001296 ++metrics_.rx_messages_count;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001297 callbacks_.OnMessageReceived(std::move(message));
1298 }
1299 }
1300}
1301
1302void DcSctpSocket::HandleSack(const CommonHeader& header,
1303 const SctpPacket::ChunkDescriptor& descriptor) {
1304 absl::optional<SackChunk> chunk = SackChunk::Parse(descriptor.data);
1305
1306 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
Victor Boivied3b186e2021-05-05 16:22:29 +02001307 TimeMs now = callbacks_.TimeMillis();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001308 SackChunk sack = ChunkValidators::Clean(*std::move(chunk));
1309
Victor Boivied3b186e2021-05-05 16:22:29 +02001310 if (tcb_->retransmission_queue().HandleSack(now, sack)) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001311 MaybeSendShutdownOrAck();
1312 // Receiving an ACK will decrease outstanding bytes (maybe now below
1313 // cwnd?) or indicate packet loss that may result in sending FORWARD-TSN.
Victor Boivied3b186e2021-05-05 16:22:29 +02001314 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001315 } else {
1316 RTC_DLOG(LS_VERBOSE) << log_prefix()
1317 << "Dropping out-of-order SACK with TSN "
1318 << *sack.cumulative_tsn_ack();
1319 }
1320 }
1321}
1322
1323void DcSctpSocket::HandleHeartbeatRequest(
1324 const CommonHeader& header,
1325 const SctpPacket::ChunkDescriptor& descriptor) {
1326 absl::optional<HeartbeatRequestChunk> chunk =
1327 HeartbeatRequestChunk::Parse(descriptor.data);
1328
1329 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1330 tcb_->heartbeat_handler().HandleHeartbeatRequest(*std::move(chunk));
1331 }
1332}
1333
1334void DcSctpSocket::HandleHeartbeatAck(
1335 const CommonHeader& header,
1336 const SctpPacket::ChunkDescriptor& descriptor) {
1337 absl::optional<HeartbeatAckChunk> chunk =
1338 HeartbeatAckChunk::Parse(descriptor.data);
1339
1340 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1341 tcb_->heartbeat_handler().HandleHeartbeatAck(*std::move(chunk));
1342 }
1343}
1344
1345void DcSctpSocket::HandleAbort(const CommonHeader& header,
1346 const SctpPacket::ChunkDescriptor& descriptor) {
1347 absl::optional<AbortChunk> chunk = AbortChunk::Parse(descriptor.data);
1348 if (ValidateParseSuccess(chunk)) {
1349 std::string error_string = ErrorCausesToString(chunk->error_causes());
1350 if (tcb_ == nullptr) {
1351 // https://tools.ietf.org/html/rfc4960#section-3.3.7
1352 // "If an endpoint receives an ABORT with a format error or no TCB is
1353 // found, it MUST silently discard it."
1354 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ABORT (" << error_string
1355 << ") on a connection with no TCB. Ignoring";
1356 return;
1357 }
1358
1359 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ABORT (" << error_string
1360 << ") - closing connection.";
1361 InternalClose(ErrorKind::kPeerReported, error_string);
1362 }
1363}
1364
1365void DcSctpSocket::HandleError(const CommonHeader& header,
1366 const SctpPacket::ChunkDescriptor& descriptor) {
1367 absl::optional<ErrorChunk> chunk = ErrorChunk::Parse(descriptor.data);
1368 if (ValidateParseSuccess(chunk)) {
1369 std::string error_string = ErrorCausesToString(chunk->error_causes());
1370 if (tcb_ == nullptr) {
1371 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ERROR (" << error_string
1372 << ") on a connection with no TCB. Ignoring";
1373 return;
1374 }
1375
1376 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ERROR: " << error_string;
1377 callbacks_.OnError(ErrorKind::kPeerReported,
1378 "Peer reported error: " + error_string);
1379 }
1380}
1381
1382void DcSctpSocket::HandleReconfig(
1383 const CommonHeader& header,
1384 const SctpPacket::ChunkDescriptor& descriptor) {
1385 absl::optional<ReConfigChunk> chunk = ReConfigChunk::Parse(descriptor.data);
1386 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1387 tcb_->stream_reset_handler().HandleReConfig(*std::move(chunk));
1388 }
1389}
1390
1391void DcSctpSocket::HandleShutdown(
1392 const CommonHeader& header,
1393 const SctpPacket::ChunkDescriptor& descriptor) {
1394 if (!ValidateParseSuccess(ShutdownChunk::Parse(descriptor.data))) {
1395 return;
1396 }
1397
1398 if (state_ == State::kClosed) {
1399 return;
1400 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1401 // https://tools.ietf.org/html/rfc4960#section-9.2
1402 // "If a SHUTDOWN is received in the COOKIE-WAIT or COOKIE ECHOED state,
1403 // the SHUTDOWN chunk SHOULD be silently discarded."
1404 } else if (state_ == State::kShutdownSent) {
1405 // https://tools.ietf.org/html/rfc4960#section-9.2
1406 // "If an endpoint is in the SHUTDOWN-SENT state and receives a
1407 // SHUTDOWN chunk from its peer, the endpoint shall respond immediately
1408 // with a SHUTDOWN ACK to its peer, and move into the SHUTDOWN-ACK-SENT
1409 // state restarting its T2-shutdown timer."
1410 SendShutdownAck();
1411 SetState(State::kShutdownAckSent, "SHUTDOWN received");
Victor Boivie50a0b122021-05-06 21:07:49 +02001412 } else if (state_ == State::kShutdownAckSent) {
1413 // TODO(webrtc:12739): This condition should be removed and handled by the
1414 // next (state_ != State::kShutdownReceived).
1415 return;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001416 } else if (state_ != State::kShutdownReceived) {
1417 RTC_DLOG(LS_VERBOSE) << log_prefix()
1418 << "Received SHUTDOWN - shutting down the socket";
1419 // https://tools.ietf.org/html/rfc4960#section-9.2
1420 // "Upon reception of the SHUTDOWN, the peer endpoint shall enter the
1421 // SHUTDOWN-RECEIVED state, stop accepting new data from its SCTP user,
1422 // and verify, by checking the Cumulative TSN Ack field of the chunk, that
1423 // all its outstanding DATA chunks have been received by the SHUTDOWN
1424 // sender."
1425 SetState(State::kShutdownReceived, "SHUTDOWN received");
1426 MaybeSendShutdownOrAck();
1427 }
1428}
1429
1430void DcSctpSocket::HandleShutdownAck(
1431 const CommonHeader& header,
1432 const SctpPacket::ChunkDescriptor& descriptor) {
1433 if (!ValidateParseSuccess(ShutdownAckChunk::Parse(descriptor.data))) {
1434 return;
1435 }
1436
1437 if (state_ == State::kShutdownSent || state_ == State::kShutdownAckSent) {
1438 // https://tools.ietf.org/html/rfc4960#section-9.2
1439 // "Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall stop
1440 // the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its peer, and
1441 // remove all record of the association."
1442
1443 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives a
1444 // SHUTDOWN ACK, it shall stop the T2-shutdown timer, send a SHUTDOWN
1445 // COMPLETE chunk to its peer, and remove all record of the association."
1446
1447 SctpPacket::Builder b = tcb_->PacketBuilder();
1448 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/false));
Victor Boivieabf61882021-08-12 15:57:49 +02001449 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001450 InternalClose(ErrorKind::kNoError, "");
1451 } else {
1452 // https://tools.ietf.org/html/rfc4960#section-8.5.1
1453 // "If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state
1454 // the procedures in Section 8.4 SHOULD be followed; in other words, it
1455 // should be treated as an Out Of The Blue packet."
1456
1457 // https://tools.ietf.org/html/rfc4960#section-8.4
1458 // "If the packet contains a SHUTDOWN ACK chunk, the receiver
1459 // should respond to the sender of the OOTB packet with a SHUTDOWN
1460 // COMPLETE. When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
1461 // packet must fill in the Verification Tag field of the outbound packet
1462 // with the Verification Tag received in the SHUTDOWN ACK and set the T
1463 // bit in the Chunk Flags to indicate that the Verification Tag is
1464 // reflected."
1465
1466 SctpPacket::Builder b(header.verification_tag, options_);
1467 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/true));
Victor Boivieabf61882021-08-12 15:57:49 +02001468 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001469 }
1470}
1471
1472void DcSctpSocket::HandleShutdownComplete(
1473 const CommonHeader& header,
1474 const SctpPacket::ChunkDescriptor& descriptor) {
1475 if (!ValidateParseSuccess(ShutdownCompleteChunk::Parse(descriptor.data))) {
1476 return;
1477 }
1478
1479 if (state_ == State::kShutdownAckSent) {
1480 // https://tools.ietf.org/html/rfc4960#section-9.2
1481 // "Upon reception of the SHUTDOWN COMPLETE chunk, the endpoint will
1482 // verify that it is in the SHUTDOWN-ACK-SENT state; if it is not, the
1483 // chunk should be discarded. If the endpoint is in the SHUTDOWN-ACK-SENT
1484 // state, the endpoint should stop the T2-shutdown timer and remove all
1485 // knowledge of the association (and thus the association enters the
1486 // CLOSED state)."
1487 InternalClose(ErrorKind::kNoError, "");
1488 }
1489}
1490
1491void DcSctpSocket::HandleForwardTsn(
1492 const CommonHeader& header,
1493 const SctpPacket::ChunkDescriptor& descriptor) {
1494 absl::optional<ForwardTsnChunk> chunk =
1495 ForwardTsnChunk::Parse(descriptor.data);
1496 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1497 HandleForwardTsnCommon(*chunk);
1498 }
1499}
1500
1501void DcSctpSocket::HandleIForwardTsn(
1502 const CommonHeader& header,
1503 const SctpPacket::ChunkDescriptor& descriptor) {
1504 absl::optional<IForwardTsnChunk> chunk =
1505 IForwardTsnChunk::Parse(descriptor.data);
1506 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1507 HandleForwardTsnCommon(*chunk);
1508 }
1509}
1510
1511void DcSctpSocket::HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk) {
1512 if (!tcb_->capabilities().partial_reliability) {
1513 SctpPacket::Builder b = tcb_->PacketBuilder();
1514 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
1515 Parameters::Builder()
1516 .Add(ProtocolViolationCause(
1517 "I-FORWARD-TSN received, but not indicated "
1518 "during connection establishment"))
1519 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001520 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001521
1522 callbacks_.OnError(ErrorKind::kProtocolViolation,
1523 "Received a FORWARD_TSN without announced peer support");
1524 return;
1525 }
1526 tcb_->data_tracker().HandleForwardTsn(chunk.new_cumulative_tsn());
1527 tcb_->reassembly_queue().Handle(chunk);
1528 // A forward TSN - for ordered streams - may allow messages to be
1529 // delivered.
1530 DeliverReassembledMessages();
1531
1532 // Processing a FORWARD_TSN might result in sending a SACK.
1533 tcb_->MaybeSendSack();
1534}
1535
1536void DcSctpSocket::MaybeSendShutdownOrAck() {
1537 if (tcb_->retransmission_queue().outstanding_bytes() != 0) {
1538 return;
1539 }
1540
1541 if (state_ == State::kShutdownPending) {
1542 // https://tools.ietf.org/html/rfc4960#section-9.2
1543 // "Once all its outstanding data has been acknowledged, the endpoint
1544 // shall send a SHUTDOWN chunk to its peer including in the Cumulative TSN
1545 // Ack field the last sequential TSN it has received from the peer. It
1546 // shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT
1547 // state.""
1548
1549 SendShutdown();
1550 t2_shutdown_->set_duration(tcb_->current_rto());
1551 t2_shutdown_->Start();
1552 SetState(State::kShutdownSent, "No more outstanding data");
1553 } else if (state_ == State::kShutdownReceived) {
1554 // https://tools.ietf.org/html/rfc4960#section-9.2
1555 // "If the receiver of the SHUTDOWN has no more outstanding DATA
1556 // chunks, the SHUTDOWN receiver MUST send a SHUTDOWN ACK and start a
1557 // T2-shutdown timer of its own, entering the SHUTDOWN-ACK-SENT state. If
1558 // the timer expires, the endpoint must resend the SHUTDOWN ACK."
1559
1560 SendShutdownAck();
1561 SetState(State::kShutdownAckSent, "No more outstanding data");
1562 }
1563}
1564
1565void DcSctpSocket::SendShutdown() {
1566 SctpPacket::Builder b = tcb_->PacketBuilder();
1567 b.Add(ShutdownChunk(tcb_->data_tracker().last_cumulative_acked_tsn()));
Victor Boivieabf61882021-08-12 15:57:49 +02001568 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001569}
1570
1571void DcSctpSocket::SendShutdownAck() {
Victor Boivieabf61882021-08-12 15:57:49 +02001572 packet_sender_.Send(tcb_->PacketBuilder().Add(ShutdownAckChunk()));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001573 t2_shutdown_->set_duration(tcb_->current_rto());
1574 t2_shutdown_->Start();
1575}
1576
1577} // namespace dcsctp