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