blob: 53838193ecda621320f1f2e2ea6fae63416ec59b [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"
Henrik Boströmb951dc62022-01-26 18:38:13 +010025#include "api/task_queue/task_queue_base.h"
Victor Boivieb6580cc2021-04-08 09:56:59 +020026#include "net/dcsctp/packet/chunk/abort_chunk.h"
27#include "net/dcsctp/packet/chunk/chunk.h"
28#include "net/dcsctp/packet/chunk/cookie_ack_chunk.h"
29#include "net/dcsctp/packet/chunk/cookie_echo_chunk.h"
30#include "net/dcsctp/packet/chunk/data_chunk.h"
31#include "net/dcsctp/packet/chunk/data_common.h"
32#include "net/dcsctp/packet/chunk/error_chunk.h"
33#include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
34#include "net/dcsctp/packet/chunk/forward_tsn_common.h"
35#include "net/dcsctp/packet/chunk/heartbeat_ack_chunk.h"
36#include "net/dcsctp/packet/chunk/heartbeat_request_chunk.h"
37#include "net/dcsctp/packet/chunk/idata_chunk.h"
38#include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h"
39#include "net/dcsctp/packet/chunk/init_ack_chunk.h"
40#include "net/dcsctp/packet/chunk/init_chunk.h"
41#include "net/dcsctp/packet/chunk/reconfig_chunk.h"
42#include "net/dcsctp/packet/chunk/sack_chunk.h"
43#include "net/dcsctp/packet/chunk/shutdown_ack_chunk.h"
44#include "net/dcsctp/packet/chunk/shutdown_chunk.h"
45#include "net/dcsctp/packet/chunk/shutdown_complete_chunk.h"
46#include "net/dcsctp/packet/chunk_validators.h"
47#include "net/dcsctp/packet/data.h"
48#include "net/dcsctp/packet/error_cause/cookie_received_while_shutting_down_cause.h"
49#include "net/dcsctp/packet/error_cause/error_cause.h"
50#include "net/dcsctp/packet/error_cause/no_user_data_cause.h"
51#include "net/dcsctp/packet/error_cause/out_of_resource_error_cause.h"
52#include "net/dcsctp/packet/error_cause/protocol_violation_cause.h"
53#include "net/dcsctp/packet/error_cause/unrecognized_chunk_type_cause.h"
54#include "net/dcsctp/packet/error_cause/user_initiated_abort_cause.h"
55#include "net/dcsctp/packet/parameter/forward_tsn_supported_parameter.h"
56#include "net/dcsctp/packet/parameter/parameter.h"
57#include "net/dcsctp/packet/parameter/state_cookie_parameter.h"
58#include "net/dcsctp/packet/parameter/supported_extensions_parameter.h"
59#include "net/dcsctp/packet/sctp_packet.h"
60#include "net/dcsctp/packet/tlv_trait.h"
61#include "net/dcsctp/public/dcsctp_message.h"
62#include "net/dcsctp/public/dcsctp_options.h"
63#include "net/dcsctp/public/dcsctp_socket.h"
64#include "net/dcsctp/public/packet_observer.h"
Victor Boiviec8680c52022-05-27 14:44:57 +020065#include "net/dcsctp/public/types.h"
Victor Boivieb6580cc2021-04-08 09:56:59 +020066#include "net/dcsctp/rx/data_tracker.h"
67#include "net/dcsctp/rx/reassembly_queue.h"
68#include "net/dcsctp/socket/callback_deferrer.h"
69#include "net/dcsctp/socket/capabilities.h"
70#include "net/dcsctp/socket/heartbeat_handler.h"
71#include "net/dcsctp/socket/state_cookie.h"
72#include "net/dcsctp/socket/stream_reset_handler.h"
73#include "net/dcsctp/socket/transmission_control_block.h"
74#include "net/dcsctp/timer/timer.h"
75#include "net/dcsctp/tx/retransmission_queue.h"
76#include "net/dcsctp/tx/send_queue.h"
77#include "rtc_base/checks.h"
78#include "rtc_base/logging.h"
79#include "rtc_base/strings/string_builder.h"
80#include "rtc_base/strings/string_format.h"
81
82namespace dcsctp {
83namespace {
84
85// https://tools.ietf.org/html/rfc4960#section-5.1
86constexpr uint32_t kMinVerificationTag = 1;
87constexpr uint32_t kMaxVerificationTag = std::numeric_limits<uint32_t>::max();
88
89// https://tools.ietf.org/html/rfc4960#section-3.3.2
90constexpr uint32_t kMinInitialTsn = 0;
91constexpr uint32_t kMaxInitialTsn = std::numeric_limits<uint32_t>::max();
92
93Capabilities GetCapabilities(const DcSctpOptions& options,
94 const Parameters& parameters) {
95 Capabilities capabilities;
96 absl::optional<SupportedExtensionsParameter> supported_extensions =
97 parameters.get<SupportedExtensionsParameter>();
98
99 if (options.enable_partial_reliability) {
100 capabilities.partial_reliability =
101 parameters.get<ForwardTsnSupportedParameter>().has_value();
102 if (supported_extensions.has_value()) {
103 capabilities.partial_reliability |=
104 supported_extensions->supports(ForwardTsnChunk::kType);
105 }
106 }
107
108 if (options.enable_message_interleaving && supported_extensions.has_value()) {
109 capabilities.message_interleaving =
110 supported_extensions->supports(IDataChunk::kType) &&
111 supported_extensions->supports(IForwardTsnChunk::kType);
112 }
113 if (supported_extensions.has_value() &&
114 supported_extensions->supports(ReConfigChunk::kType)) {
115 capabilities.reconfig = true;
116 }
117 return capabilities;
118}
119
120void AddCapabilityParameters(const DcSctpOptions& options,
121 Parameters::Builder& builder) {
122 std::vector<uint8_t> chunk_types = {ReConfigChunk::kType};
123
124 if (options.enable_partial_reliability) {
125 builder.Add(ForwardTsnSupportedParameter());
126 chunk_types.push_back(ForwardTsnChunk::kType);
127 }
128 if (options.enable_message_interleaving) {
129 chunk_types.push_back(IDataChunk::kType);
130 chunk_types.push_back(IForwardTsnChunk::kType);
131 }
132 builder.Add(SupportedExtensionsParameter(std::move(chunk_types)));
133}
134
135TieTag MakeTieTag(DcSctpSocketCallbacks& cb) {
136 uint32_t tie_tag_upper =
137 cb.GetRandomInt(0, std::numeric_limits<uint32_t>::max());
138 uint32_t tie_tag_lower =
139 cb.GetRandomInt(1, std::numeric_limits<uint32_t>::max());
140 return TieTag(static_cast<uint64_t>(tie_tag_upper) << 32 |
141 static_cast<uint64_t>(tie_tag_lower));
142}
Victor Boivief4fa1662021-09-24 23:01:21 +0200143
144SctpImplementation DeterminePeerImplementation(
145 rtc::ArrayView<const uint8_t> cookie) {
146 if (cookie.size() > 8) {
147 absl::string_view magic(reinterpret_cast<const char*>(cookie.data()), 8);
148 if (magic == "dcSCTP00") {
149 return SctpImplementation::kDcsctp;
150 }
151 if (magic == "KAME-BSD") {
152 return SctpImplementation::kUsrSctp;
153 }
154 }
155 return SctpImplementation::kOther;
156}
Victor Boivieb6580cc2021-04-08 09:56:59 +0200157} // namespace
158
159DcSctpSocket::DcSctpSocket(absl::string_view log_prefix,
160 DcSctpSocketCallbacks& callbacks,
161 std::unique_ptr<PacketObserver> packet_observer,
162 const DcSctpOptions& options)
163 : log_prefix_(std::string(log_prefix) + ": "),
164 packet_observer_(std::move(packet_observer)),
165 options_(options),
166 callbacks_(callbacks),
Henrik Boströmb951dc62022-01-26 18:38:13 +0100167 timer_manager_([this](webrtc::TaskQueueBase::DelayPrecision precision) {
168 return callbacks_.CreateTimeout(precision);
169 }),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200170 t1_init_(timer_manager_.CreateTimer(
171 "t1-init",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200172 absl::bind_front(&DcSctpSocket::OnInitTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200173 TimerOptions(options.t1_init_timeout,
174 TimerBackoffAlgorithm::kExponential,
175 options.max_init_retransmits))),
176 t1_cookie_(timer_manager_.CreateTimer(
177 "t1-cookie",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200178 absl::bind_front(&DcSctpSocket::OnCookieTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200179 TimerOptions(options.t1_cookie_timeout,
180 TimerBackoffAlgorithm::kExponential,
181 options.max_init_retransmits))),
182 t2_shutdown_(timer_manager_.CreateTimer(
183 "t2-shutdown",
Victor Boivie600bb8c2021-08-12 15:43:13 +0200184 absl::bind_front(&DcSctpSocket::OnShutdownTimerExpiry, this),
Victor Boivieb6580cc2021-04-08 09:56:59 +0200185 TimerOptions(options.t2_shutdown_timeout,
186 TimerBackoffAlgorithm::kExponential,
187 options.max_retransmissions))),
Victor Boivieabf61882021-08-12 15:57:49 +0200188 packet_sender_(callbacks_,
189 absl::bind_front(&DcSctpSocket::OnSentPacket, this)),
Victor Boivie00c61422022-05-27 09:55:41 +0200190 send_queue_(log_prefix_,
191 &callbacks_,
192 options_.max_send_buffer_size,
193 options_.mtu,
194 options_.default_stream_priority,
195 options_.total_buffered_amount_low_threshold) {}
Victor Boivieb6580cc2021-04-08 09:56:59 +0200196
197std::string DcSctpSocket::log_prefix() const {
Florent Castelli29ff3ef2022-02-17 16:23:56 +0100198 return log_prefix_ + "[" + std::string(ToString(state_)) + "] ";
Victor Boivieb6580cc2021-04-08 09:56:59 +0200199}
200
201bool DcSctpSocket::IsConsistent() const {
Victor Boivie54e4e352021-09-15 10:42:26 +0200202 if (tcb_ != nullptr && tcb_->reassembly_queue().HasMessages()) {
203 return false;
204 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200205 switch (state_) {
206 case State::kClosed:
207 return (tcb_ == nullptr && !t1_init_->is_running() &&
208 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
209 case State::kCookieWait:
210 return (tcb_ == nullptr && t1_init_->is_running() &&
211 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
212 case State::kCookieEchoed:
213 return (tcb_ != nullptr && !t1_init_->is_running() &&
214 t1_cookie_->is_running() && !t2_shutdown_->is_running() &&
Victor Boiviec20f1562021-06-16 12:52:42 +0200215 tcb_->has_cookie_echo_chunk());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200216 case State::kEstablished:
217 return (tcb_ != nullptr && !t1_init_->is_running() &&
218 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
219 case State::kShutdownPending:
220 return (tcb_ != nullptr && !t1_init_->is_running() &&
221 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
222 case State::kShutdownSent:
223 return (tcb_ != nullptr && !t1_init_->is_running() &&
224 !t1_cookie_->is_running() && t2_shutdown_->is_running());
225 case State::kShutdownReceived:
226 return (tcb_ != nullptr && !t1_init_->is_running() &&
227 !t1_cookie_->is_running() && !t2_shutdown_->is_running());
228 case State::kShutdownAckSent:
229 return (tcb_ != nullptr && !t1_init_->is_running() &&
230 !t1_cookie_->is_running() && t2_shutdown_->is_running());
231 }
232}
233
234constexpr absl::string_view DcSctpSocket::ToString(DcSctpSocket::State state) {
235 switch (state) {
236 case DcSctpSocket::State::kClosed:
237 return "CLOSED";
238 case DcSctpSocket::State::kCookieWait:
239 return "COOKIE_WAIT";
240 case DcSctpSocket::State::kCookieEchoed:
241 return "COOKIE_ECHOED";
242 case DcSctpSocket::State::kEstablished:
243 return "ESTABLISHED";
244 case DcSctpSocket::State::kShutdownPending:
245 return "SHUTDOWN_PENDING";
246 case DcSctpSocket::State::kShutdownSent:
247 return "SHUTDOWN_SENT";
248 case DcSctpSocket::State::kShutdownReceived:
249 return "SHUTDOWN_RECEIVED";
250 case DcSctpSocket::State::kShutdownAckSent:
251 return "SHUTDOWN_ACK_SENT";
252 }
253}
254
255void DcSctpSocket::SetState(State state, absl::string_view reason) {
256 if (state_ != state) {
257 RTC_DLOG(LS_VERBOSE) << log_prefix_ << "Socket state changed from "
258 << ToString(state_) << " to " << ToString(state)
259 << " due to " << reason;
260 state_ = state;
261 }
262}
263
264void DcSctpSocket::SendInit() {
265 Parameters::Builder params_builder;
266 AddCapabilityParameters(options_, params_builder);
267 InitChunk init(/*initiate_tag=*/connect_params_.verification_tag,
268 /*a_rwnd=*/options_.max_receiver_window_buffer_size,
269 options_.announced_maximum_outgoing_streams,
270 options_.announced_maximum_incoming_streams,
271 connect_params_.initial_tsn, params_builder.Build());
272 SctpPacket::Builder b(VerificationTag(0), options_);
273 b.Add(init);
Victor Boivieabf61882021-08-12 15:57:49 +0200274 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200275}
276
277void DcSctpSocket::MakeConnectionParameters() {
278 VerificationTag new_verification_tag(
279 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
280 TSN initial_tsn(callbacks_.GetRandomInt(kMinInitialTsn, kMaxInitialTsn));
281 connect_params_.initial_tsn = initial_tsn;
282 connect_params_.verification_tag = new_verification_tag;
283}
284
285void DcSctpSocket::Connect() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200286 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200287 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
288
Victor Boivieb6580cc2021-04-08 09:56:59 +0200289 if (state_ == State::kClosed) {
290 MakeConnectionParameters();
291 RTC_DLOG(LS_INFO)
292 << log_prefix()
293 << rtc::StringFormat(
294 "Connecting. my_verification_tag=%08x, my_initial_tsn=%u",
295 *connect_params_.verification_tag, *connect_params_.initial_tsn);
296 SendInit();
297 t1_init_->Start();
298 SetState(State::kCookieWait, "Connect called");
299 } else {
300 RTC_DLOG(LS_WARNING) << log_prefix()
301 << "Called Connect on a socket that is not closed";
302 }
303 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200304}
305
Victor Boivie2cffde72022-06-27 20:35:37 +0000306void DcSctpSocket::CreateTransmissionControlBlock(
307 const Capabilities& capabilities,
308 VerificationTag my_verification_tag,
309 TSN my_initial_tsn,
310 VerificationTag peer_verification_tag,
311 TSN peer_initial_tsn,
312 size_t a_rwnd,
313 TieTag tie_tag) {
Victor Boivie5b2556e2022-05-13 15:31:14 +0200314 metrics_.uses_message_interleaving = capabilities.message_interleaving;
Victor Boivie2cffde72022-06-27 20:35:37 +0000315 tcb_ = std::make_unique<TransmissionControlBlock>(
316 timer_manager_, log_prefix_, options_, capabilities, callbacks_,
317 send_queue_, my_verification_tag, my_initial_tsn, peer_verification_tag,
318 peer_initial_tsn, a_rwnd, tie_tag, packet_sender_,
319 [this]() { return state_ == State::kEstablished; });
320 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Created TCB: " << tcb_->ToString();
321}
322
Sergey Sukhanov43972812021-09-17 15:32:48 +0200323void DcSctpSocket::RestoreFromState(const DcSctpSocketHandoverState& state) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200324 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200325 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
326
Sergey Sukhanov43972812021-09-17 15:32:48 +0200327 if (state_ != State::kClosed) {
328 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
329 "Only closed socket can be restored from state");
330 } else {
331 if (state.socket_state ==
332 DcSctpSocketHandoverState::SocketState::kConnected) {
333 VerificationTag my_verification_tag =
334 VerificationTag(state.my_verification_tag);
335 connect_params_.verification_tag = my_verification_tag;
336
337 Capabilities capabilities;
338 capabilities.partial_reliability = state.capabilities.partial_reliability;
339 capabilities.message_interleaving =
340 state.capabilities.message_interleaving;
341 capabilities.reconfig = state.capabilities.reconfig;
342
Sergey Sukhanov72435322021-09-21 13:31:09 +0200343 send_queue_.RestoreFromState(state);
344
Victor Boivie2cffde72022-06-27 20:35:37 +0000345 CreateTransmissionControlBlock(
346 capabilities, my_verification_tag, TSN(state.my_initial_tsn),
Sergey Sukhanov43972812021-09-17 15:32:48 +0200347 VerificationTag(state.peer_verification_tag),
348 TSN(state.peer_initial_tsn), static_cast<size_t>(0),
Victor Boivie2cffde72022-06-27 20:35:37 +0000349 TieTag(state.tie_tag));
350
351 tcb_->RestoreFromState(state);
Sergey Sukhanov43972812021-09-17 15:32:48 +0200352
353 SetState(State::kEstablished, "restored from handover state");
354 callbacks_.OnConnected();
355 }
356 }
357
358 RTC_DCHECK(IsConsistent());
Sergey Sukhanov43972812021-09-17 15:32:48 +0200359}
360
Victor Boivieb6580cc2021-04-08 09:56:59 +0200361void DcSctpSocket::Shutdown() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200362 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200363 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
364
Victor Boivieb6580cc2021-04-08 09:56:59 +0200365 if (tcb_ != nullptr) {
366 // https://tools.ietf.org/html/rfc4960#section-9.2
367 // "Upon receipt of the SHUTDOWN primitive from its upper layer, the
368 // endpoint enters the SHUTDOWN-PENDING state and remains there until all
369 // outstanding data has been acknowledged by its peer."
Victor Boivie50a0b122021-05-06 21:07:49 +0200370
371 // TODO(webrtc:12739): Remove this check, as it just hides the problem that
372 // the socket can transition from ShutdownSent to ShutdownPending, or
373 // ShutdownAckSent to ShutdownPending which is illegal.
374 if (state_ != State::kShutdownSent && state_ != State::kShutdownAckSent) {
375 SetState(State::kShutdownPending, "Shutdown called");
376 t1_init_->Stop();
377 t1_cookie_->Stop();
378 MaybeSendShutdownOrAck();
379 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200380 } else {
381 // Connection closed before even starting to connect, or during the initial
382 // connection phase. There is no outstanding data, so the socket can just
383 // be closed (stopping any connection timers, if any), as this is the
384 // client's intention, by calling Shutdown.
385 InternalClose(ErrorKind::kNoError, "");
386 }
387 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200388}
389
390void DcSctpSocket::Close() {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200391 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200392 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
393
Victor Boivieb6580cc2021-04-08 09:56:59 +0200394 if (state_ != State::kClosed) {
395 if (tcb_ != nullptr) {
396 SctpPacket::Builder b = tcb_->PacketBuilder();
397 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
398 Parameters::Builder()
399 .Add(UserInitiatedAbortCause("Close called"))
400 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +0200401 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200402 }
403 InternalClose(ErrorKind::kNoError, "");
404 } else {
405 RTC_DLOG(LS_INFO) << log_prefix() << "Called Close on a closed socket";
406 }
407 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200408}
409
410void DcSctpSocket::CloseConnectionBecauseOfTooManyTransmissionErrors() {
Victor Boivieabf61882021-08-12 15:57:49 +0200411 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200412 true, Parameters::Builder()
413 .Add(UserInitiatedAbortCause("Too many retransmissions"))
414 .Build())));
415 InternalClose(ErrorKind::kTooManyRetries, "Too many retransmissions");
416}
417
418void DcSctpSocket::InternalClose(ErrorKind error, absl::string_view message) {
419 if (state_ != State::kClosed) {
420 t1_init_->Stop();
421 t1_cookie_->Stop();
422 t2_shutdown_->Stop();
423 tcb_ = nullptr;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200424
425 if (error == ErrorKind::kNoError) {
426 callbacks_.OnClosed();
427 } else {
428 callbacks_.OnAborted(error, message);
429 }
430 SetState(State::kClosed, message);
431 }
432 // This method's purpose is to abort/close and make it consistent by ensuring
433 // that e.g. all timers really are stopped.
434 RTC_DCHECK(IsConsistent());
435}
436
Victor Boivie7e897ae2022-05-02 13:04:37 +0200437void DcSctpSocket::SetStreamPriority(StreamID stream_id,
438 StreamPriority priority) {
439 RTC_DCHECK_RUN_ON(&thread_checker_);
440 send_queue_.SetStreamPriority(stream_id, priority);
441}
442StreamPriority DcSctpSocket::GetStreamPriority(StreamID stream_id) const {
443 RTC_DCHECK_RUN_ON(&thread_checker_);
444 return send_queue_.GetStreamPriority(stream_id);
445}
446
Victor Boivieb6580cc2021-04-08 09:56:59 +0200447SendStatus DcSctpSocket::Send(DcSctpMessage message,
448 const SendOptions& send_options) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200449 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200450 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
Victor Boiviec8680c52022-05-27 14:44:57 +0200451 LifecycleId lifecycle_id = send_options.lifecycle_id;
Victor Boivie15a0c882021-09-28 21:38:34 +0200452
Victor Boivieb6580cc2021-04-08 09:56:59 +0200453 if (message.payload().empty()) {
Victor Boiviec8680c52022-05-27 14:44:57 +0200454 if (lifecycle_id.IsSet()) {
455 callbacks_.OnLifecycleEnd(lifecycle_id);
456 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200457 callbacks_.OnError(ErrorKind::kProtocolViolation,
458 "Unable to send empty message");
459 return SendStatus::kErrorMessageEmpty;
460 }
461 if (message.payload().size() > options_.max_message_size) {
Victor Boiviec8680c52022-05-27 14:44:57 +0200462 if (lifecycle_id.IsSet()) {
463 callbacks_.OnLifecycleEnd(lifecycle_id);
464 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200465 callbacks_.OnError(ErrorKind::kProtocolViolation,
466 "Unable to send too large message");
467 return SendStatus::kErrorMessageTooLarge;
468 }
469 if (state_ == State::kShutdownPending || state_ == State::kShutdownSent ||
470 state_ == State::kShutdownReceived || state_ == State::kShutdownAckSent) {
471 // https://tools.ietf.org/html/rfc4960#section-9.2
472 // "An endpoint should reject any new data request from its upper layer
473 // if it is in the SHUTDOWN-PENDING, SHUTDOWN-SENT, SHUTDOWN-RECEIVED, or
474 // SHUTDOWN-ACK-SENT state."
Victor Boiviec8680c52022-05-27 14:44:57 +0200475 if (lifecycle_id.IsSet()) {
476 callbacks_.OnLifecycleEnd(lifecycle_id);
477 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200478 callbacks_.OnError(ErrorKind::kWrongSequence,
479 "Unable to send message as the socket is shutting down");
480 return SendStatus::kErrorShuttingDown;
481 }
482 if (send_queue_.IsFull()) {
Victor Boiviec8680c52022-05-27 14:44:57 +0200483 if (lifecycle_id.IsSet()) {
484 callbacks_.OnLifecycleEnd(lifecycle_id);
485 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200486 callbacks_.OnError(ErrorKind::kResourceExhaustion,
487 "Unable to send message as the send queue is full");
488 return SendStatus::kErrorResourceExhaustion;
489 }
490
Victor Boivied3b186e2021-05-05 16:22:29 +0200491 TimeMs now = callbacks_.TimeMillis();
Victor Boivied4716ea2021-08-09 12:26:32 +0200492 ++metrics_.tx_messages_count;
Victor Boivied3b186e2021-05-05 16:22:29 +0200493 send_queue_.Add(now, std::move(message), send_options);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200494 if (tcb_ != nullptr) {
Victor Boivied3b186e2021-05-05 16:22:29 +0200495 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200496 }
497
498 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200499 return SendStatus::kSuccess;
500}
501
502ResetStreamsStatus DcSctpSocket::ResetStreams(
503 rtc::ArrayView<const StreamID> outgoing_streams) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200504 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200505 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
506
Victor Boivieb6580cc2021-04-08 09:56:59 +0200507 if (tcb_ == nullptr) {
508 callbacks_.OnError(ErrorKind::kWrongSequence,
509 "Can't reset streams as the socket is not connected");
510 return ResetStreamsStatus::kNotConnected;
511 }
512 if (!tcb_->capabilities().reconfig) {
513 callbacks_.OnError(ErrorKind::kUnsupportedOperation,
514 "Can't reset streams as the peer doesn't support it");
515 return ResetStreamsStatus::kNotSupported;
516 }
517
518 tcb_->stream_reset_handler().ResetStreams(outgoing_streams);
Victor Boivief9e116f2022-03-31 17:15:03 +0200519 MaybeSendResetStreamsRequest();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200520
521 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200522 return ResetStreamsStatus::kPerformed;
523}
524
525SocketState DcSctpSocket::state() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200526 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200527 switch (state_) {
528 case State::kClosed:
529 return SocketState::kClosed;
530 case State::kCookieWait:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200531 case State::kCookieEchoed:
532 return SocketState::kConnecting;
533 case State::kEstablished:
534 return SocketState::kConnected;
535 case State::kShutdownPending:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200536 case State::kShutdownSent:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200537 case State::kShutdownReceived:
Victor Boivieb6580cc2021-04-08 09:56:59 +0200538 case State::kShutdownAckSent:
539 return SocketState::kShuttingDown;
540 }
541}
542
Florent Castelli0810b052021-05-04 20:12:52 +0200543void DcSctpSocket::SetMaxMessageSize(size_t max_message_size) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200544 RTC_DCHECK_RUN_ON(&thread_checker_);
Florent Castelli0810b052021-05-04 20:12:52 +0200545 options_.max_message_size = max_message_size;
546}
547
Victor Boivie236ac502021-05-20 19:34:18 +0200548size_t DcSctpSocket::buffered_amount(StreamID stream_id) const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200549 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200550 return send_queue_.buffered_amount(stream_id);
551}
552
553size_t DcSctpSocket::buffered_amount_low_threshold(StreamID stream_id) const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200554 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200555 return send_queue_.buffered_amount_low_threshold(stream_id);
556}
557
558void DcSctpSocket::SetBufferedAmountLowThreshold(StreamID stream_id,
559 size_t bytes) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200560 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie236ac502021-05-20 19:34:18 +0200561 send_queue_.SetBufferedAmountLowThreshold(stream_id, bytes);
562}
563
Victor Boivief7fc71d2022-05-13 14:27:55 +0200564absl::optional<Metrics> DcSctpSocket::GetMetrics() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200565 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivied4716ea2021-08-09 12:26:32 +0200566
Victor Boivief7fc71d2022-05-13 14:27:55 +0200567 if (tcb_ == nullptr) {
568 return absl::nullopt;
Victor Boivied4716ea2021-08-09 12:26:32 +0200569 }
570
Victor Boivief7fc71d2022-05-13 14:27:55 +0200571 Metrics metrics = metrics_;
572 metrics.cwnd_bytes = tcb_->cwnd();
573 metrics.srtt_ms = tcb_->current_srtt().value();
574 size_t packet_payload_size =
575 options_.mtu - SctpPacket::kHeaderSize - DataChunk::kHeaderSize;
576 metrics.unack_data_count =
577 tcb_->retransmission_queue().outstanding_items() +
578 (send_queue_.total_buffered_amount() + packet_payload_size - 1) /
579 packet_payload_size;
580 metrics.peer_rwnd_bytes = tcb_->retransmission_queue().rwnd();
581
Victor Boivied4716ea2021-08-09 12:26:32 +0200582 return metrics;
583}
584
Victor Boivieb6580cc2021-04-08 09:56:59 +0200585void DcSctpSocket::MaybeSendShutdownOnPacketReceived(const SctpPacket& packet) {
586 if (state_ == State::kShutdownSent) {
587 bool has_data_chunk =
588 std::find_if(packet.descriptors().begin(), packet.descriptors().end(),
589 [](const SctpPacket::ChunkDescriptor& descriptor) {
590 return descriptor.type == DataChunk::kType;
591 }) != packet.descriptors().end();
592 if (has_data_chunk) {
593 // https://tools.ietf.org/html/rfc4960#section-9.2
594 // "While in the SHUTDOWN-SENT state, the SHUTDOWN sender MUST immediately
595 // respond to each received packet containing one or more DATA chunks with
596 // a SHUTDOWN chunk and restart the T2-shutdown timer.""
597 SendShutdown();
598 t2_shutdown_->set_duration(tcb_->current_rto());
599 t2_shutdown_->Start();
600 }
601 }
602}
603
Victor Boivief9e116f2022-03-31 17:15:03 +0200604void DcSctpSocket::MaybeSendResetStreamsRequest() {
605 absl::optional<ReConfigChunk> reconfig =
606 tcb_->stream_reset_handler().MakeStreamResetRequest();
607 if (reconfig.has_value()) {
608 SctpPacket::Builder builder = tcb_->PacketBuilder();
609 builder.Add(*reconfig);
610 packet_sender_.Send(builder);
611 }
612}
613
Victor Boivieb6580cc2021-04-08 09:56:59 +0200614bool DcSctpSocket::ValidatePacket(const SctpPacket& packet) {
615 const CommonHeader& header = packet.common_header();
616 VerificationTag my_verification_tag =
617 tcb_ != nullptr ? tcb_->my_verification_tag() : VerificationTag(0);
618
619 if (header.verification_tag == VerificationTag(0)) {
620 if (packet.descriptors().size() == 1 &&
621 packet.descriptors()[0].type == InitChunk::kType) {
622 // https://tools.ietf.org/html/rfc4960#section-8.5.1
623 // "When an endpoint receives an SCTP packet with the Verification Tag
624 // set to 0, it should verify that the packet contains only an INIT chunk.
625 // Otherwise, the receiver MUST silently discard the packet.""
626 return true;
627 }
628 callbacks_.OnError(
629 ErrorKind::kParseFailed,
630 "Only a single INIT chunk can be present in packets sent on "
631 "verification_tag = 0");
632 return false;
633 }
634
635 if (packet.descriptors().size() == 1 &&
636 packet.descriptors()[0].type == AbortChunk::kType) {
637 // https://tools.ietf.org/html/rfc4960#section-8.5.1
638 // "The receiver of an ABORT MUST accept the packet if the Verification
639 // Tag field of the packet matches its own tag and the T bit is not set OR
640 // if it is set to its peer's tag and the T bit is set in the Chunk Flags.
641 // Otherwise, the receiver MUST silently discard the packet and take no
642 // further action."
643 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
644 if (t_bit && tcb_ == nullptr) {
645 // Can't verify the tag - assume it's okey.
646 return true;
647 }
648 if ((!t_bit && header.verification_tag == my_verification_tag) ||
649 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
650 return true;
651 }
652 callbacks_.OnError(ErrorKind::kParseFailed,
653 "ABORT chunk verification tag was wrong");
654 return false;
655 }
656
657 if (packet.descriptors()[0].type == InitAckChunk::kType) {
658 if (header.verification_tag == connect_params_.verification_tag) {
659 return true;
660 }
661 callbacks_.OnError(
662 ErrorKind::kParseFailed,
663 rtc::StringFormat(
664 "Packet has invalid verification tag: %08x, expected %08x",
665 *header.verification_tag, *connect_params_.verification_tag));
666 return false;
667 }
668
669 if (packet.descriptors()[0].type == CookieEchoChunk::kType) {
670 // Handled in chunk handler (due to RFC 4960, section 5.2.4).
671 return true;
672 }
673
674 if (packet.descriptors().size() == 1 &&
675 packet.descriptors()[0].type == ShutdownCompleteChunk::kType) {
676 // https://tools.ietf.org/html/rfc4960#section-8.5.1
677 // "The receiver of a SHUTDOWN COMPLETE shall accept the packet if the
678 // Verification Tag field of the packet matches its own tag and the T bit is
679 // not set OR if it is set to its peer's tag and the T bit is set in the
680 // Chunk Flags. Otherwise, the receiver MUST silently discard the packet
681 // and take no further action."
682 bool t_bit = (packet.descriptors()[0].flags & 0x01) != 0;
683 if (t_bit && tcb_ == nullptr) {
684 // Can't verify the tag - assume it's okey.
685 return true;
686 }
687 if ((!t_bit && header.verification_tag == my_verification_tag) ||
688 (t_bit && header.verification_tag == tcb_->peer_verification_tag())) {
689 return true;
690 }
691 callbacks_.OnError(ErrorKind::kParseFailed,
692 "SHUTDOWN_COMPLETE chunk verification tag was wrong");
693 return false;
694 }
695
696 // https://tools.ietf.org/html/rfc4960#section-8.5
697 // "When receiving an SCTP packet, the endpoint MUST ensure that the value
698 // in the Verification Tag field of the received SCTP packet matches its own
699 // tag. If the received Verification Tag value does not match the receiver's
700 // own tag value, the receiver shall silently discard the packet and shall not
701 // process it any further..."
702 if (header.verification_tag == my_verification_tag) {
703 return true;
704 }
705
706 callbacks_.OnError(
707 ErrorKind::kParseFailed,
708 rtc::StringFormat(
709 "Packet has invalid verification tag: %08x, expected %08x",
710 *header.verification_tag, *my_verification_tag));
711 return false;
712}
713
714void DcSctpSocket::HandleTimeout(TimeoutID timeout_id) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200715 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200716 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
717
Victor Boivieb6580cc2021-04-08 09:56:59 +0200718 timer_manager_.HandleTimeout(timeout_id);
719
720 if (tcb_ != nullptr && tcb_->HasTooManyTxErrors()) {
721 // Tearing down the TCB has to be done outside the handlers.
722 CloseConnectionBecauseOfTooManyTransmissionErrors();
723 }
724
725 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200726}
727
728void DcSctpSocket::ReceivePacket(rtc::ArrayView<const uint8_t> data) {
Victor Boivie5755f3e2021-09-29 22:23:15 +0200729 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +0200730 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
731
Victor Boivied4716ea2021-08-09 12:26:32 +0200732 ++metrics_.rx_packets_count;
733
Victor Boivieb6580cc2021-04-08 09:56:59 +0200734 if (packet_observer_ != nullptr) {
735 packet_observer_->OnReceivedPacket(callbacks_.TimeMillis(), data);
736 }
737
738 absl::optional<SctpPacket> packet =
739 SctpPacket::Parse(data, options_.disable_checksum_verification);
740 if (!packet.has_value()) {
741 // https://tools.ietf.org/html/rfc4960#section-6.8
742 // "The default procedure for handling invalid SCTP packets is to
743 // silently discard them."
744 callbacks_.OnError(ErrorKind::kParseFailed,
745 "Failed to parse received SCTP packet");
746 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200747 return;
748 }
749
750 if (RTC_DLOG_IS_ON) {
751 for (const auto& descriptor : packet->descriptors()) {
752 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received "
753 << DebugConvertChunkToString(descriptor.data);
754 }
755 }
756
757 if (!ValidatePacket(*packet)) {
758 RTC_DLOG(LS_VERBOSE) << log_prefix()
759 << "Packet failed verification tag check - dropping";
760 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200761 return;
762 }
763
764 MaybeSendShutdownOnPacketReceived(*packet);
765
766 for (const auto& descriptor : packet->descriptors()) {
767 if (!Dispatch(packet->common_header(), descriptor)) {
768 break;
769 }
770 }
771
772 if (tcb_ != nullptr) {
773 tcb_->data_tracker().ObservePacketEnd();
774 tcb_->MaybeSendSack();
775 }
776
777 RTC_DCHECK(IsConsistent());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200778}
779
780void DcSctpSocket::DebugPrintOutgoing(rtc::ArrayView<const uint8_t> payload) {
781 auto packet = SctpPacket::Parse(payload);
782 RTC_DCHECK(packet.has_value());
783
784 for (const auto& desc : packet->descriptors()) {
785 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Sent "
786 << DebugConvertChunkToString(desc.data);
787 }
788}
789
790bool DcSctpSocket::Dispatch(const CommonHeader& header,
791 const SctpPacket::ChunkDescriptor& descriptor) {
792 switch (descriptor.type) {
793 case DataChunk::kType:
794 HandleData(header, descriptor);
795 break;
796 case InitChunk::kType:
797 HandleInit(header, descriptor);
798 break;
799 case InitAckChunk::kType:
800 HandleInitAck(header, descriptor);
801 break;
802 case SackChunk::kType:
803 HandleSack(header, descriptor);
804 break;
805 case HeartbeatRequestChunk::kType:
806 HandleHeartbeatRequest(header, descriptor);
807 break;
808 case HeartbeatAckChunk::kType:
809 HandleHeartbeatAck(header, descriptor);
810 break;
811 case AbortChunk::kType:
812 HandleAbort(header, descriptor);
813 break;
814 case ErrorChunk::kType:
815 HandleError(header, descriptor);
816 break;
817 case CookieEchoChunk::kType:
818 HandleCookieEcho(header, descriptor);
819 break;
820 case CookieAckChunk::kType:
821 HandleCookieAck(header, descriptor);
822 break;
823 case ShutdownChunk::kType:
824 HandleShutdown(header, descriptor);
825 break;
826 case ShutdownAckChunk::kType:
827 HandleShutdownAck(header, descriptor);
828 break;
829 case ShutdownCompleteChunk::kType:
830 HandleShutdownComplete(header, descriptor);
831 break;
832 case ReConfigChunk::kType:
833 HandleReconfig(header, descriptor);
834 break;
835 case ForwardTsnChunk::kType:
836 HandleForwardTsn(header, descriptor);
837 break;
838 case IDataChunk::kType:
839 HandleIData(header, descriptor);
840 break;
841 case IForwardTsnChunk::kType:
Victor Boivie69c83cd2022-03-05 08:18:26 +0100842 HandleIForwardTsn(header, descriptor);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200843 break;
844 default:
845 return HandleUnrecognizedChunk(descriptor);
846 }
847 return true;
848}
849
850bool DcSctpSocket::HandleUnrecognizedChunk(
851 const SctpPacket::ChunkDescriptor& descriptor) {
852 bool report_as_error = (descriptor.type & 0x40) != 0;
853 bool continue_processing = (descriptor.type & 0x80) != 0;
854 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received unknown chunk: "
855 << static_cast<int>(descriptor.type);
856 if (report_as_error) {
857 rtc::StringBuilder sb;
858 sb << "Received unknown chunk of type: "
859 << static_cast<int>(descriptor.type) << " with report-error bit set";
860 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
861 RTC_DLOG(LS_VERBOSE)
862 << log_prefix()
863 << "Unknown chunk, with type indicating it should be reported.";
864
865 // https://tools.ietf.org/html/rfc4960#section-3.2
866 // "... report in an ERROR chunk using the 'Unrecognized Chunk Type'
867 // cause."
868 if (tcb_ != nullptr) {
869 // Need TCB - this chunk must be sent with a correct verification tag.
Victor Boivieabf61882021-08-12 15:57:49 +0200870 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200871 ErrorChunk(Parameters::Builder()
872 .Add(UnrecognizedChunkTypeCause(std::vector<uint8_t>(
873 descriptor.data.begin(), descriptor.data.end())))
874 .Build())));
875 }
876 }
877 if (!continue_processing) {
878 // https://tools.ietf.org/html/rfc4960#section-3.2
879 // "Stop processing this SCTP packet and discard it, do not process any
880 // further chunks within it."
881 RTC_DLOG(LS_VERBOSE) << log_prefix()
882 << "Unknown chunk, with type indicating not to "
883 "process any further chunks";
884 }
885
886 return continue_processing;
887}
888
889absl::optional<DurationMs> DcSctpSocket::OnInitTimerExpiry() {
890 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_init_->name()
891 << " has expired: " << t1_init_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200892 << "/" << t1_init_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200893 RTC_DCHECK(state_ == State::kCookieWait);
894
895 if (t1_init_->is_running()) {
896 SendInit();
897 } else {
898 InternalClose(ErrorKind::kTooManyRetries, "No INIT_ACK received");
899 }
900 RTC_DCHECK(IsConsistent());
901 return absl::nullopt;
902}
903
904absl::optional<DurationMs> DcSctpSocket::OnCookieTimerExpiry() {
905 // https://tools.ietf.org/html/rfc4960#section-4
906 // "If the T1-cookie timer expires, the endpoint MUST retransmit COOKIE
907 // ECHO and restart the T1-cookie timer without changing state. This MUST
908 // be repeated up to 'Max.Init.Retransmits' times. After that, the endpoint
909 // MUST abort the initialization process and report the error to the SCTP
910 // user."
911 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t1_cookie_->name()
912 << " has expired: " << t1_cookie_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200913 << "/"
914 << t1_cookie_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200915
916 RTC_DCHECK(state_ == State::kCookieEchoed);
917
918 if (t1_cookie_->is_running()) {
Victor Boiviec20f1562021-06-16 12:52:42 +0200919 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +0200920 } else {
921 InternalClose(ErrorKind::kTooManyRetries, "No COOKIE_ACK received");
922 }
923
924 RTC_DCHECK(IsConsistent());
925 return absl::nullopt;
926}
927
928absl::optional<DurationMs> DcSctpSocket::OnShutdownTimerExpiry() {
929 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Timer " << t2_shutdown_->name()
930 << " has expired: " << t2_shutdown_->expiration_count()
Victor Boivie9680d292021-08-30 10:23:49 +0200931 << "/"
932 << t2_shutdown_->options().max_restarts.value_or(-1);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200933
Victor Boivie914925f2021-05-07 11:22:50 +0200934 if (!t2_shutdown_->is_running()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +0200935 // https://tools.ietf.org/html/rfc4960#section-9.2
936 // "An endpoint should limit the number of retransmissions of the SHUTDOWN
937 // chunk to the protocol parameter 'Association.Max.Retrans'. If this
938 // threshold is exceeded, the endpoint should destroy the TCB..."
939
Victor Boivieabf61882021-08-12 15:57:49 +0200940 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +0200941 AbortChunk(true, Parameters::Builder()
942 .Add(UserInitiatedAbortCause(
943 "Too many retransmissions of SHUTDOWN"))
944 .Build())));
945
946 InternalClose(ErrorKind::kTooManyRetries, "No SHUTDOWN_ACK received");
Victor Boivie914925f2021-05-07 11:22:50 +0200947 RTC_DCHECK(IsConsistent());
948 return absl::nullopt;
Victor Boivieb6580cc2021-04-08 09:56:59 +0200949 }
Victor Boivie914925f2021-05-07 11:22:50 +0200950
951 // https://tools.ietf.org/html/rfc4960#section-9.2
952 // "If the timer expires, the endpoint must resend the SHUTDOWN with the
953 // updated last sequential TSN received from its peer."
954 SendShutdown();
Victor Boivieb6580cc2021-04-08 09:56:59 +0200955 RTC_DCHECK(IsConsistent());
956 return tcb_->current_rto();
957}
958
Victor Boivieabf61882021-08-12 15:57:49 +0200959void DcSctpSocket::OnSentPacket(rtc::ArrayView<const uint8_t> packet,
960 SendPacketStatus status) {
961 // The packet observer is invoked even if the packet was failed to be sent, to
962 // indicate an attempt was made.
Victor Boivieb6580cc2021-04-08 09:56:59 +0200963 if (packet_observer_ != nullptr) {
Victor Boivieabf61882021-08-12 15:57:49 +0200964 packet_observer_->OnSentPacket(callbacks_.TimeMillis(), packet);
Victor Boivieb6580cc2021-04-08 09:56:59 +0200965 }
Victor Boivieabf61882021-08-12 15:57:49 +0200966
967 if (status == SendPacketStatus::kSuccess) {
968 if (RTC_DLOG_IS_ON) {
969 DebugPrintOutgoing(packet);
970 }
971
972 // The heartbeat interval timer is restarted for every sent packet, to
973 // fire when the outgoing channel is inactive.
974 if (tcb_ != nullptr) {
975 tcb_->heartbeat_handler().RestartTimer();
976 }
977
978 ++metrics_.tx_packets_count;
979 }
Victor Boivieb6580cc2021-04-08 09:56:59 +0200980}
981
982bool DcSctpSocket::ValidateHasTCB() {
983 if (tcb_ != nullptr) {
984 return true;
985 }
986
987 callbacks_.OnError(
988 ErrorKind::kNotConnected,
989 "Received unexpected commands on socket that is not connected");
990 return false;
991}
992
993void DcSctpSocket::ReportFailedToParseChunk(int chunk_type) {
994 rtc::StringBuilder sb;
995 sb << "Failed to parse chunk of type: " << chunk_type;
996 callbacks_.OnError(ErrorKind::kParseFailed, sb.str());
997}
998
999void DcSctpSocket::HandleData(const CommonHeader& header,
1000 const SctpPacket::ChunkDescriptor& descriptor) {
1001 absl::optional<DataChunk> chunk = DataChunk::Parse(descriptor.data);
1002 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1003 HandleDataCommon(*chunk);
1004 }
1005}
1006
1007void DcSctpSocket::HandleIData(const CommonHeader& header,
1008 const SctpPacket::ChunkDescriptor& descriptor) {
1009 absl::optional<IDataChunk> chunk = IDataChunk::Parse(descriptor.data);
1010 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1011 HandleDataCommon(*chunk);
1012 }
1013}
1014
1015void DcSctpSocket::HandleDataCommon(AnyDataChunk& chunk) {
1016 TSN tsn = chunk.tsn();
1017 AnyDataChunk::ImmediateAckFlag immediate_ack = chunk.options().immediate_ack;
1018 Data data = std::move(chunk).extract();
1019
Victor Boivie4b7024b2021-12-01 18:57:22 +00001020 if (data.payload.empty()) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001021 // Empty DATA chunks are illegal.
Victor Boivieabf61882021-08-12 15:57:49 +02001022 packet_sender_.Send(tcb_->PacketBuilder().Add(
Victor Boivieb6580cc2021-04-08 09:56:59 +02001023 ErrorChunk(Parameters::Builder().Add(NoUserDataCause(tsn)).Build())));
1024 callbacks_.OnError(ErrorKind::kProtocolViolation,
1025 "Received DATA chunk with no user data");
1026 return;
1027 }
1028
1029 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Handle DATA, queue_size="
1030 << tcb_->reassembly_queue().queued_bytes()
1031 << ", water_mark="
1032 << tcb_->reassembly_queue().watermark_bytes()
1033 << ", full=" << tcb_->reassembly_queue().is_full()
1034 << ", above="
1035 << tcb_->reassembly_queue().is_above_watermark();
1036
1037 if (tcb_->reassembly_queue().is_full()) {
1038 // If the reassembly queue is full, there is nothing that can be done. The
1039 // specification only allows dropping gap-ack-blocks, and that's not
1040 // likely to help as the socket has been trying to fill gaps since the
1041 // watermark was reached.
Victor Boivieabf61882021-08-12 15:57:49 +02001042 packet_sender_.Send(tcb_->PacketBuilder().Add(AbortChunk(
Victor Boivieb6580cc2021-04-08 09:56:59 +02001043 true, Parameters::Builder().Add(OutOfResourceErrorCause()).Build())));
1044 InternalClose(ErrorKind::kResourceExhaustion,
1045 "Reassembly Queue is exhausted");
1046 return;
1047 }
1048
1049 if (tcb_->reassembly_queue().is_above_watermark()) {
1050 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Is above high watermark";
1051 // If the reassembly queue is above its high watermark, only accept data
1052 // chunks that increase its cumulative ack tsn in an attempt to fill gaps
1053 // to deliver messages.
1054 if (!tcb_->data_tracker().will_increase_cum_ack_tsn(tsn)) {
1055 RTC_DLOG(LS_VERBOSE) << log_prefix()
1056 << "Rejected data because of exceeding watermark";
1057 tcb_->data_tracker().ForceImmediateSack();
1058 return;
1059 }
1060 }
1061
1062 if (!tcb_->data_tracker().IsTSNValid(tsn)) {
1063 RTC_DLOG(LS_VERBOSE) << log_prefix()
1064 << "Rejected data because of failing TSN validity";
1065 return;
1066 }
1067
Victor Boivie568bc232022-03-20 19:59:03 +01001068 if (tcb_->data_tracker().Observe(tsn, immediate_ack)) {
1069 tcb_->reassembly_queue().MaybeResetStreamsDeferred(
1070 tcb_->data_tracker().last_cumulative_acked_tsn());
1071 tcb_->reassembly_queue().Add(tsn, std::move(data));
1072 DeliverReassembledMessages();
1073 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001074}
1075
1076void DcSctpSocket::HandleInit(const CommonHeader& header,
1077 const SctpPacket::ChunkDescriptor& descriptor) {
1078 absl::optional<InitChunk> chunk = InitChunk::Parse(descriptor.data);
1079 if (!ValidateParseSuccess(chunk)) {
1080 return;
1081 }
1082
1083 if (chunk->initiate_tag() == VerificationTag(0) ||
1084 chunk->nbr_outbound_streams() == 0 || chunk->nbr_inbound_streams() == 0) {
1085 // https://tools.ietf.org/html/rfc4960#section-3.3.2
1086 // "If the value of the Initiate Tag in a received INIT chunk is found
1087 // to be 0, the receiver MUST treat it as an error and close the
1088 // association by transmitting an ABORT."
1089
1090 // "A receiver of an INIT with the OS value set to 0 SHOULD abort the
1091 // association."
1092
1093 // "A receiver of an INIT with the MIS value of 0 SHOULD abort the
1094 // association."
1095
Victor Boivieabf61882021-08-12 15:57:49 +02001096 packet_sender_.Send(
1097 SctpPacket::Builder(VerificationTag(0), options_)
1098 .Add(AbortChunk(
1099 /*filled_in_verification_tag=*/false,
1100 Parameters::Builder()
1101 .Add(ProtocolViolationCause("INIT malformed"))
1102 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001103 InternalClose(ErrorKind::kProtocolViolation, "Received invalid INIT");
1104 return;
1105 }
1106
1107 if (state_ == State::kShutdownAckSent) {
1108 // https://tools.ietf.org/html/rfc4960#section-9.2
1109 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives an
1110 // INIT chunk (e.g., if the SHUTDOWN COMPLETE was lost) with source and
1111 // destination transport addresses (either in the IP addresses or in the
1112 // INIT chunk) that belong to this association, it should discard the INIT
1113 // chunk and retransmit the SHUTDOWN ACK chunk."
1114 RTC_DLOG(LS_VERBOSE) << log_prefix()
1115 << "Received Init indicating lost ShutdownComplete";
1116 SendShutdownAck();
1117 return;
1118 }
1119
1120 TieTag tie_tag(0);
1121 if (state_ == State::kClosed) {
1122 RTC_DLOG(LS_VERBOSE) << log_prefix()
1123 << "Received Init in closed state (normal)";
1124
1125 MakeConnectionParameters();
1126 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1127 // https://tools.ietf.org/html/rfc4960#section-5.2.1
1128 // "This usually indicates an initialization collision, i.e., each
1129 // endpoint is attempting, at about the same time, to establish an
1130 // association with the other endpoint. Upon receipt of an INIT in the
1131 // COOKIE-WAIT state, an endpoint MUST respond with an INIT ACK using the
1132 // same parameters it sent in its original INIT chunk (including its
1133 // Initiate Tag, unchanged). When responding, the endpoint MUST send the
1134 // INIT ACK back to the same address that the original INIT (sent by this
1135 // endpoint) was sent."
1136 RTC_DLOG(LS_VERBOSE) << log_prefix()
1137 << "Received Init indicating simultaneous connections";
1138 } else {
1139 RTC_DCHECK(tcb_ != nullptr);
1140 // https://tools.ietf.org/html/rfc4960#section-5.2.2
1141 // "The outbound SCTP packet containing this INIT ACK MUST carry a
1142 // Verification Tag value equal to the Initiate Tag found in the
1143 // unexpected INIT. And the INIT ACK MUST contain a new Initiate Tag
1144 // (randomly generated; see Section 5.3.1). Other parameters for the
1145 // endpoint SHOULD be copied from the existing parameters of the
1146 // association (e.g., number of outbound streams) into the INIT ACK and
1147 // cookie."
1148 RTC_DLOG(LS_VERBOSE) << log_prefix()
1149 << "Received Init indicating restarted connection";
1150 // Create a new verification tag - different from the previous one.
1151 for (int tries = 0; tries < 10; ++tries) {
1152 connect_params_.verification_tag = VerificationTag(
1153 callbacks_.GetRandomInt(kMinVerificationTag, kMaxVerificationTag));
1154 if (connect_params_.verification_tag != tcb_->my_verification_tag()) {
1155 break;
1156 }
1157 }
1158
1159 // Make the initial TSN make a large jump, so that there is no overlap
1160 // with the old and new association.
1161 connect_params_.initial_tsn =
1162 TSN(*tcb_->retransmission_queue().next_tsn() + 1000000);
1163 tie_tag = tcb_->tie_tag();
1164 }
1165
1166 RTC_DLOG(LS_VERBOSE)
1167 << log_prefix()
1168 << rtc::StringFormat(
1169 "Proceeding with connection. my_verification_tag=%08x, "
1170 "my_initial_tsn=%u, peer_verification_tag=%08x, "
1171 "peer_initial_tsn=%u",
1172 *connect_params_.verification_tag, *connect_params_.initial_tsn,
1173 *chunk->initiate_tag(), *chunk->initial_tsn());
1174
1175 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1176
1177 SctpPacket::Builder b(chunk->initiate_tag(), options_);
1178 Parameters::Builder params_builder =
1179 Parameters::Builder().Add(StateCookieParameter(
1180 StateCookie(chunk->initiate_tag(), chunk->initial_tsn(),
1181 chunk->a_rwnd(), tie_tag, capabilities)
1182 .Serialize()));
1183 AddCapabilityParameters(options_, params_builder);
1184
1185 InitAckChunk init_ack(/*initiate_tag=*/connect_params_.verification_tag,
1186 options_.max_receiver_window_buffer_size,
1187 options_.announced_maximum_outgoing_streams,
1188 options_.announced_maximum_incoming_streams,
1189 connect_params_.initial_tsn, params_builder.Build());
1190 b.Add(init_ack);
Victor Boivieabf61882021-08-12 15:57:49 +02001191 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001192}
1193
Victor Boivieb6580cc2021-04-08 09:56:59 +02001194void DcSctpSocket::HandleInitAck(
1195 const CommonHeader& header,
1196 const SctpPacket::ChunkDescriptor& descriptor) {
1197 absl::optional<InitAckChunk> chunk = InitAckChunk::Parse(descriptor.data);
1198 if (!ValidateParseSuccess(chunk)) {
1199 return;
1200 }
1201
1202 if (state_ != State::kCookieWait) {
1203 // https://tools.ietf.org/html/rfc4960#section-5.2.3
1204 // "If an INIT ACK is received by an endpoint in any state other than
1205 // the COOKIE-WAIT state, the endpoint should discard the INIT ACK chunk."
1206 RTC_DLOG(LS_VERBOSE) << log_prefix()
1207 << "Received INIT_ACK in unexpected state";
1208 return;
1209 }
1210
1211 auto cookie = chunk->parameters().get<StateCookieParameter>();
1212 if (!cookie.has_value()) {
Victor Boivieabf61882021-08-12 15:57:49 +02001213 packet_sender_.Send(
1214 SctpPacket::Builder(connect_params_.verification_tag, options_)
1215 .Add(AbortChunk(
1216 /*filled_in_verification_tag=*/false,
1217 Parameters::Builder()
1218 .Add(ProtocolViolationCause("INIT-ACK malformed"))
1219 .Build())));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001220 InternalClose(ErrorKind::kProtocolViolation,
1221 "InitAck chunk doesn't contain a cookie");
1222 return;
1223 }
1224 Capabilities capabilities = GetCapabilities(options_, chunk->parameters());
1225 t1_init_->Stop();
1226
Victor Boivief7fc71d2022-05-13 14:27:55 +02001227 metrics_.peer_implementation = DeterminePeerImplementation(cookie->data());
Victor Boivief4fa1662021-09-24 23:01:21 +02001228
Victor Boivie2cffde72022-06-27 20:35:37 +00001229 // If the connection is re-established (peer restarted, but re-used old
1230 // connection), make sure that all message identifiers are reset and any
1231 // partly sent message is re-sent in full. The same is true when the socket
1232 // is closed and later re-opened, which never happens in WebRTC, but is a
1233 // valid operation on the SCTP level. Note that in case of handover, the
1234 // send queue is already re-configured, and shouldn't be reset.
1235 send_queue_.Reset();
1236
1237 CreateTransmissionControlBlock(capabilities, connect_params_.verification_tag,
1238 connect_params_.initial_tsn,
1239 chunk->initiate_tag(), chunk->initial_tsn(),
1240 chunk->a_rwnd(), MakeTieTag(callbacks_));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001241
1242 SetState(State::kCookieEchoed, "INIT_ACK received");
1243
1244 // The connection isn't fully established just yet.
Victor Boiviec20f1562021-06-16 12:52:42 +02001245 tcb_->SetCookieEchoChunk(CookieEchoChunk(cookie->data()));
1246 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001247 t1_cookie_->Start();
1248}
1249
1250void DcSctpSocket::HandleCookieEcho(
1251 const CommonHeader& header,
1252 const SctpPacket::ChunkDescriptor& descriptor) {
1253 absl::optional<CookieEchoChunk> chunk =
1254 CookieEchoChunk::Parse(descriptor.data);
1255 if (!ValidateParseSuccess(chunk)) {
1256 return;
1257 }
1258
1259 absl::optional<StateCookie> cookie =
1260 StateCookie::Deserialize(chunk->cookie());
1261 if (!cookie.has_value()) {
1262 callbacks_.OnError(ErrorKind::kParseFailed, "Failed to parse state cookie");
1263 return;
1264 }
1265
1266 if (tcb_ != nullptr) {
1267 if (!HandleCookieEchoWithTCB(header, *cookie)) {
1268 return;
1269 }
1270 } else {
1271 if (header.verification_tag != connect_params_.verification_tag) {
1272 callbacks_.OnError(
1273 ErrorKind::kParseFailed,
1274 rtc::StringFormat(
1275 "Received CookieEcho with invalid verification tag: %08x, "
1276 "expected %08x",
1277 *header.verification_tag, *connect_params_.verification_tag));
1278 return;
1279 }
1280 }
1281
1282 // The init timer can be running on simultaneous connections.
1283 t1_init_->Stop();
1284 t1_cookie_->Stop();
1285 if (state_ != State::kEstablished) {
Victor Boiviec20f1562021-06-16 12:52:42 +02001286 if (tcb_ != nullptr) {
1287 tcb_->ClearCookieEchoChunk();
1288 }
Victor Boivieb6580cc2021-04-08 09:56:59 +02001289 SetState(State::kEstablished, "COOKIE_ECHO received");
1290 callbacks_.OnConnected();
1291 }
1292
1293 if (tcb_ == nullptr) {
Victor Boivie2cffde72022-06-27 20:35:37 +00001294 // If the connection is re-established (peer restarted, but re-used old
1295 // connection), make sure that all message identifiers are reset and any
1296 // partly sent message is re-sent in full. The same is true when the socket
1297 // is closed and later re-opened, which never happens in WebRTC, but is a
1298 // valid operation on the SCTP level. Note that in case of handover, the
1299 // send queue is already re-configured, and shouldn't be reset.
1300 send_queue_.Reset();
1301
1302 CreateTransmissionControlBlock(
1303 cookie->capabilities(), connect_params_.verification_tag,
Victor Boivieb6580cc2021-04-08 09:56:59 +02001304 connect_params_.initial_tsn, cookie->initiate_tag(),
Victor Boivie2cffde72022-06-27 20:35:37 +00001305 cookie->initial_tsn(), cookie->a_rwnd(), MakeTieTag(callbacks_));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001306 }
1307
1308 SctpPacket::Builder b = tcb_->PacketBuilder();
1309 b.Add(CookieAckChunk());
1310
1311 // https://tools.ietf.org/html/rfc4960#section-5.1
1312 // "A COOKIE ACK chunk may be bundled with any pending DATA chunks (and/or
1313 // SACK chunks), but the COOKIE ACK chunk MUST be the first chunk in the
1314 // packet."
Victor Boivied3b186e2021-05-05 16:22:29 +02001315 tcb_->SendBufferedPackets(b, callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001316}
1317
1318bool DcSctpSocket::HandleCookieEchoWithTCB(const CommonHeader& header,
1319 const StateCookie& cookie) {
1320 RTC_DLOG(LS_VERBOSE) << log_prefix()
1321 << "Handling CookieEchoChunk with TCB. local_tag="
1322 << *tcb_->my_verification_tag()
1323 << ", peer_tag=" << *header.verification_tag
1324 << ", tcb_tag=" << *tcb_->peer_verification_tag()
1325 << ", cookie_tag=" << *cookie.initiate_tag()
1326 << ", local_tie_tag=" << *tcb_->tie_tag()
1327 << ", peer_tie_tag=" << *cookie.tie_tag();
1328 // https://tools.ietf.org/html/rfc4960#section-5.2.4
1329 // "Handle a COOKIE ECHO when a TCB Exists"
1330 if (header.verification_tag != tcb_->my_verification_tag() &&
1331 tcb_->peer_verification_tag() != cookie.initiate_tag() &&
1332 cookie.tie_tag() == tcb_->tie_tag()) {
1333 // "A) In this case, the peer may have restarted."
1334 if (state_ == State::kShutdownAckSent) {
1335 // "If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes
1336 // that the peer has restarted ... it MUST NOT set up a new association
1337 // but instead resend the SHUTDOWN ACK and send an ERROR chunk with a
1338 // "Cookie Received While Shutting Down" error cause to its peer."
1339 SctpPacket::Builder b(cookie.initiate_tag(), options_);
1340 b.Add(ShutdownAckChunk());
1341 b.Add(ErrorChunk(Parameters::Builder()
1342 .Add(CookieReceivedWhileShuttingDownCause())
1343 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001344 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001345 callbacks_.OnError(ErrorKind::kWrongSequence,
1346 "Received COOKIE-ECHO while shutting down");
1347 return false;
1348 }
1349
1350 RTC_DLOG(LS_VERBOSE) << log_prefix()
1351 << "Received COOKIE-ECHO indicating a restarted peer";
1352
Victor Boivieb6580cc2021-04-08 09:56:59 +02001353 tcb_ = nullptr;
1354 callbacks_.OnConnectionRestarted();
1355 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1356 tcb_->peer_verification_tag() != cookie.initiate_tag()) {
1357 // TODO(boivie): Handle the peer_tag == 0?
1358 // "B) In this case, both sides may be attempting to start an
1359 // association at about the same time, but the peer endpoint started its
1360 // INIT after responding to the local endpoint's INIT."
1361 RTC_DLOG(LS_VERBOSE)
1362 << log_prefix()
1363 << "Received COOKIE-ECHO indicating simultaneous connections";
1364 tcb_ = nullptr;
1365 } else if (header.verification_tag != tcb_->my_verification_tag() &&
1366 tcb_->peer_verification_tag() == cookie.initiate_tag() &&
1367 cookie.tie_tag() == TieTag(0)) {
1368 // "C) In this case, the local endpoint's cookie has arrived late.
1369 // Before it arrived, the local endpoint sent an INIT and received an
1370 // INIT ACK and finally sent a COOKIE ECHO with the peer's same tag but
1371 // a new tag of its own. The cookie should be silently discarded. The
1372 // endpoint SHOULD NOT change states and should leave any timers
1373 // running."
1374 RTC_DLOG(LS_VERBOSE)
1375 << log_prefix()
1376 << "Received COOKIE-ECHO indicating a late COOKIE-ECHO. Discarding";
1377 return false;
1378 } else if (header.verification_tag == tcb_->my_verification_tag() &&
1379 tcb_->peer_verification_tag() == cookie.initiate_tag()) {
1380 // "D) When both local and remote tags match, the endpoint should enter
1381 // the ESTABLISHED state, if it is in the COOKIE-ECHOED state. It
1382 // should stop any cookie timer that may be running and send a COOKIE
1383 // ACK."
1384 RTC_DLOG(LS_VERBOSE)
1385 << log_prefix()
1386 << "Received duplicate COOKIE-ECHO, probably because of peer not "
1387 "receiving COOKIE-ACK and retransmitting COOKIE-ECHO. Continuing.";
1388 }
1389 return true;
1390}
1391
1392void DcSctpSocket::HandleCookieAck(
1393 const CommonHeader& header,
1394 const SctpPacket::ChunkDescriptor& descriptor) {
1395 absl::optional<CookieAckChunk> chunk = CookieAckChunk::Parse(descriptor.data);
1396 if (!ValidateParseSuccess(chunk)) {
1397 return;
1398 }
1399
1400 if (state_ != State::kCookieEchoed) {
1401 // https://tools.ietf.org/html/rfc4960#section-5.2.5
1402 // "At any state other than COOKIE-ECHOED, an endpoint should silently
1403 // discard a received COOKIE ACK chunk."
1404 RTC_DLOG(LS_VERBOSE) << log_prefix()
1405 << "Received COOKIE_ACK not in COOKIE_ECHOED state";
1406 return;
1407 }
1408
1409 // RFC 4960, Errata ID: 4400
1410 t1_cookie_->Stop();
Victor Boiviec20f1562021-06-16 12:52:42 +02001411 tcb_->ClearCookieEchoChunk();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001412 SetState(State::kEstablished, "COOKIE_ACK received");
Victor Boivied3b186e2021-05-05 16:22:29 +02001413 tcb_->SendBufferedPackets(callbacks_.TimeMillis());
Victor Boivieb6580cc2021-04-08 09:56:59 +02001414 callbacks_.OnConnected();
1415}
1416
1417void DcSctpSocket::DeliverReassembledMessages() {
1418 if (tcb_->reassembly_queue().HasMessages()) {
1419 for (auto& message : tcb_->reassembly_queue().FlushMessages()) {
Victor Boivied4716ea2021-08-09 12:26:32 +02001420 ++metrics_.rx_messages_count;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001421 callbacks_.OnMessageReceived(std::move(message));
1422 }
1423 }
1424}
1425
1426void DcSctpSocket::HandleSack(const CommonHeader& header,
1427 const SctpPacket::ChunkDescriptor& descriptor) {
1428 absl::optional<SackChunk> chunk = SackChunk::Parse(descriptor.data);
1429
1430 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
Victor Boivied3b186e2021-05-05 16:22:29 +02001431 TimeMs now = callbacks_.TimeMillis();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001432 SackChunk sack = ChunkValidators::Clean(*std::move(chunk));
1433
Victor Boivied3b186e2021-05-05 16:22:29 +02001434 if (tcb_->retransmission_queue().HandleSack(now, sack)) {
Victor Boivieb6580cc2021-04-08 09:56:59 +02001435 MaybeSendShutdownOrAck();
Victor Boivie5e354d92022-04-22 16:28:33 +02001436 // Receiving an ACK may make the socket go into fast recovery mode.
1437 // https://datatracker.ietf.org/doc/html/rfc4960#section-7.2.4
1438 // "Determine how many of the earliest (i.e., lowest TSN) DATA chunks
1439 // marked for retransmission will fit into a single packet, subject to
1440 // constraint of the path MTU of the destination transport address to
1441 // which the packet is being sent. Call this value K. Retransmit those K
1442 // DATA chunks in a single packet. When a Fast Retransmit is being
1443 // performed, the sender SHOULD ignore the value of cwnd and SHOULD NOT
1444 // delay retransmission for this single packet."
1445 tcb_->MaybeSendFastRetransmit();
1446
Victor Boivieb6580cc2021-04-08 09:56:59 +02001447 // Receiving an ACK will decrease outstanding bytes (maybe now below
1448 // cwnd?) or indicate packet loss that may result in sending FORWARD-TSN.
Victor Boivied3b186e2021-05-05 16:22:29 +02001449 tcb_->SendBufferedPackets(now);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001450 } else {
1451 RTC_DLOG(LS_VERBOSE) << log_prefix()
1452 << "Dropping out-of-order SACK with TSN "
1453 << *sack.cumulative_tsn_ack();
1454 }
1455 }
1456}
1457
1458void DcSctpSocket::HandleHeartbeatRequest(
1459 const CommonHeader& header,
1460 const SctpPacket::ChunkDescriptor& descriptor) {
1461 absl::optional<HeartbeatRequestChunk> chunk =
1462 HeartbeatRequestChunk::Parse(descriptor.data);
1463
1464 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1465 tcb_->heartbeat_handler().HandleHeartbeatRequest(*std::move(chunk));
1466 }
1467}
1468
1469void DcSctpSocket::HandleHeartbeatAck(
1470 const CommonHeader& header,
1471 const SctpPacket::ChunkDescriptor& descriptor) {
1472 absl::optional<HeartbeatAckChunk> chunk =
1473 HeartbeatAckChunk::Parse(descriptor.data);
1474
1475 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1476 tcb_->heartbeat_handler().HandleHeartbeatAck(*std::move(chunk));
1477 }
1478}
1479
1480void DcSctpSocket::HandleAbort(const CommonHeader& header,
1481 const SctpPacket::ChunkDescriptor& descriptor) {
1482 absl::optional<AbortChunk> chunk = AbortChunk::Parse(descriptor.data);
1483 if (ValidateParseSuccess(chunk)) {
1484 std::string error_string = ErrorCausesToString(chunk->error_causes());
1485 if (tcb_ == nullptr) {
1486 // https://tools.ietf.org/html/rfc4960#section-3.3.7
1487 // "If an endpoint receives an ABORT with a format error or no TCB is
1488 // found, it MUST silently discard it."
1489 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ABORT (" << error_string
1490 << ") on a connection with no TCB. Ignoring";
1491 return;
1492 }
1493
1494 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ABORT (" << error_string
1495 << ") - closing connection.";
1496 InternalClose(ErrorKind::kPeerReported, error_string);
1497 }
1498}
1499
1500void DcSctpSocket::HandleError(const CommonHeader& header,
1501 const SctpPacket::ChunkDescriptor& descriptor) {
1502 absl::optional<ErrorChunk> chunk = ErrorChunk::Parse(descriptor.data);
1503 if (ValidateParseSuccess(chunk)) {
1504 std::string error_string = ErrorCausesToString(chunk->error_causes());
1505 if (tcb_ == nullptr) {
1506 RTC_DLOG(LS_VERBOSE) << log_prefix() << "Received ERROR (" << error_string
1507 << ") on a connection with no TCB. Ignoring";
1508 return;
1509 }
1510
1511 RTC_DLOG(LS_WARNING) << log_prefix() << "Received ERROR: " << error_string;
1512 callbacks_.OnError(ErrorKind::kPeerReported,
1513 "Peer reported error: " + error_string);
1514 }
1515}
1516
1517void DcSctpSocket::HandleReconfig(
1518 const CommonHeader& header,
1519 const SctpPacket::ChunkDescriptor& descriptor) {
1520 absl::optional<ReConfigChunk> chunk = ReConfigChunk::Parse(descriptor.data);
1521 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1522 tcb_->stream_reset_handler().HandleReConfig(*std::move(chunk));
Victor Boivief9e116f2022-03-31 17:15:03 +02001523 // Handling this response may result in outgoing stream resets finishing
1524 // (either successfully or with failure). If there still are pending streams
1525 // that were waiting for this request to finish, continue resetting them.
1526 MaybeSendResetStreamsRequest();
Victor Boivieb6580cc2021-04-08 09:56:59 +02001527 }
1528}
1529
1530void DcSctpSocket::HandleShutdown(
1531 const CommonHeader& header,
1532 const SctpPacket::ChunkDescriptor& descriptor) {
1533 if (!ValidateParseSuccess(ShutdownChunk::Parse(descriptor.data))) {
1534 return;
1535 }
1536
1537 if (state_ == State::kClosed) {
1538 return;
1539 } else if (state_ == State::kCookieWait || state_ == State::kCookieEchoed) {
1540 // https://tools.ietf.org/html/rfc4960#section-9.2
1541 // "If a SHUTDOWN is received in the COOKIE-WAIT or COOKIE ECHOED state,
1542 // the SHUTDOWN chunk SHOULD be silently discarded."
1543 } else if (state_ == State::kShutdownSent) {
1544 // https://tools.ietf.org/html/rfc4960#section-9.2
1545 // "If an endpoint is in the SHUTDOWN-SENT state and receives a
1546 // SHUTDOWN chunk from its peer, the endpoint shall respond immediately
1547 // with a SHUTDOWN ACK to its peer, and move into the SHUTDOWN-ACK-SENT
1548 // state restarting its T2-shutdown timer."
1549 SendShutdownAck();
1550 SetState(State::kShutdownAckSent, "SHUTDOWN received");
Victor Boivie50a0b122021-05-06 21:07:49 +02001551 } else if (state_ == State::kShutdownAckSent) {
1552 // TODO(webrtc:12739): This condition should be removed and handled by the
1553 // next (state_ != State::kShutdownReceived).
1554 return;
Victor Boivieb6580cc2021-04-08 09:56:59 +02001555 } else if (state_ != State::kShutdownReceived) {
1556 RTC_DLOG(LS_VERBOSE) << log_prefix()
1557 << "Received SHUTDOWN - shutting down the socket";
1558 // https://tools.ietf.org/html/rfc4960#section-9.2
1559 // "Upon reception of the SHUTDOWN, the peer endpoint shall enter the
1560 // SHUTDOWN-RECEIVED state, stop accepting new data from its SCTP user,
1561 // and verify, by checking the Cumulative TSN Ack field of the chunk, that
1562 // all its outstanding DATA chunks have been received by the SHUTDOWN
1563 // sender."
1564 SetState(State::kShutdownReceived, "SHUTDOWN received");
1565 MaybeSendShutdownOrAck();
1566 }
1567}
1568
1569void DcSctpSocket::HandleShutdownAck(
1570 const CommonHeader& header,
1571 const SctpPacket::ChunkDescriptor& descriptor) {
1572 if (!ValidateParseSuccess(ShutdownAckChunk::Parse(descriptor.data))) {
1573 return;
1574 }
1575
1576 if (state_ == State::kShutdownSent || state_ == State::kShutdownAckSent) {
1577 // https://tools.ietf.org/html/rfc4960#section-9.2
1578 // "Upon the receipt of the SHUTDOWN ACK, the SHUTDOWN sender shall stop
1579 // the T2-shutdown timer, send a SHUTDOWN COMPLETE chunk to its peer, and
1580 // remove all record of the association."
1581
1582 // "If an endpoint is in the SHUTDOWN-ACK-SENT state and receives a
1583 // SHUTDOWN ACK, it shall stop the T2-shutdown timer, send a SHUTDOWN
1584 // COMPLETE chunk to its peer, and remove all record of the association."
1585
1586 SctpPacket::Builder b = tcb_->PacketBuilder();
1587 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/false));
Victor Boivieabf61882021-08-12 15:57:49 +02001588 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001589 InternalClose(ErrorKind::kNoError, "");
1590 } else {
1591 // https://tools.ietf.org/html/rfc4960#section-8.5.1
1592 // "If the receiver is in COOKIE-ECHOED or COOKIE-WAIT state
1593 // the procedures in Section 8.4 SHOULD be followed; in other words, it
1594 // should be treated as an Out Of The Blue packet."
1595
1596 // https://tools.ietf.org/html/rfc4960#section-8.4
1597 // "If the packet contains a SHUTDOWN ACK chunk, the receiver
1598 // should respond to the sender of the OOTB packet with a SHUTDOWN
1599 // COMPLETE. When sending the SHUTDOWN COMPLETE, the receiver of the OOTB
1600 // packet must fill in the Verification Tag field of the outbound packet
1601 // with the Verification Tag received in the SHUTDOWN ACK and set the T
1602 // bit in the Chunk Flags to indicate that the Verification Tag is
1603 // reflected."
1604
1605 SctpPacket::Builder b(header.verification_tag, options_);
1606 b.Add(ShutdownCompleteChunk(/*tag_reflected=*/true));
Victor Boivieabf61882021-08-12 15:57:49 +02001607 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001608 }
1609}
1610
1611void DcSctpSocket::HandleShutdownComplete(
1612 const CommonHeader& header,
1613 const SctpPacket::ChunkDescriptor& descriptor) {
1614 if (!ValidateParseSuccess(ShutdownCompleteChunk::Parse(descriptor.data))) {
1615 return;
1616 }
1617
1618 if (state_ == State::kShutdownAckSent) {
1619 // https://tools.ietf.org/html/rfc4960#section-9.2
1620 // "Upon reception of the SHUTDOWN COMPLETE chunk, the endpoint will
1621 // verify that it is in the SHUTDOWN-ACK-SENT state; if it is not, the
1622 // chunk should be discarded. If the endpoint is in the SHUTDOWN-ACK-SENT
1623 // state, the endpoint should stop the T2-shutdown timer and remove all
1624 // knowledge of the association (and thus the association enters the
1625 // CLOSED state)."
1626 InternalClose(ErrorKind::kNoError, "");
1627 }
1628}
1629
1630void DcSctpSocket::HandleForwardTsn(
1631 const CommonHeader& header,
1632 const SctpPacket::ChunkDescriptor& descriptor) {
1633 absl::optional<ForwardTsnChunk> chunk =
1634 ForwardTsnChunk::Parse(descriptor.data);
1635 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1636 HandleForwardTsnCommon(*chunk);
1637 }
1638}
1639
1640void DcSctpSocket::HandleIForwardTsn(
1641 const CommonHeader& header,
1642 const SctpPacket::ChunkDescriptor& descriptor) {
1643 absl::optional<IForwardTsnChunk> chunk =
1644 IForwardTsnChunk::Parse(descriptor.data);
1645 if (ValidateParseSuccess(chunk) && ValidateHasTCB()) {
1646 HandleForwardTsnCommon(*chunk);
1647 }
1648}
1649
1650void DcSctpSocket::HandleForwardTsnCommon(const AnyForwardTsnChunk& chunk) {
1651 if (!tcb_->capabilities().partial_reliability) {
1652 SctpPacket::Builder b = tcb_->PacketBuilder();
1653 b.Add(AbortChunk(/*filled_in_verification_tag=*/true,
1654 Parameters::Builder()
1655 .Add(ProtocolViolationCause(
1656 "I-FORWARD-TSN received, but not indicated "
1657 "during connection establishment"))
1658 .Build()));
Victor Boivieabf61882021-08-12 15:57:49 +02001659 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001660
1661 callbacks_.OnError(ErrorKind::kProtocolViolation,
1662 "Received a FORWARD_TSN without announced peer support");
1663 return;
1664 }
1665 tcb_->data_tracker().HandleForwardTsn(chunk.new_cumulative_tsn());
1666 tcb_->reassembly_queue().Handle(chunk);
1667 // A forward TSN - for ordered streams - may allow messages to be
1668 // delivered.
1669 DeliverReassembledMessages();
1670
1671 // Processing a FORWARD_TSN might result in sending a SACK.
1672 tcb_->MaybeSendSack();
1673}
1674
1675void DcSctpSocket::MaybeSendShutdownOrAck() {
1676 if (tcb_->retransmission_queue().outstanding_bytes() != 0) {
1677 return;
1678 }
1679
1680 if (state_ == State::kShutdownPending) {
1681 // https://tools.ietf.org/html/rfc4960#section-9.2
1682 // "Once all its outstanding data has been acknowledged, the endpoint
1683 // shall send a SHUTDOWN chunk to its peer including in the Cumulative TSN
1684 // Ack field the last sequential TSN it has received from the peer. It
1685 // shall then start the T2-shutdown timer and enter the SHUTDOWN-SENT
1686 // state.""
1687
1688 SendShutdown();
1689 t2_shutdown_->set_duration(tcb_->current_rto());
1690 t2_shutdown_->Start();
1691 SetState(State::kShutdownSent, "No more outstanding data");
1692 } else if (state_ == State::kShutdownReceived) {
1693 // https://tools.ietf.org/html/rfc4960#section-9.2
1694 // "If the receiver of the SHUTDOWN has no more outstanding DATA
1695 // chunks, the SHUTDOWN receiver MUST send a SHUTDOWN ACK and start a
1696 // T2-shutdown timer of its own, entering the SHUTDOWN-ACK-SENT state. If
1697 // the timer expires, the endpoint must resend the SHUTDOWN ACK."
1698
1699 SendShutdownAck();
1700 SetState(State::kShutdownAckSent, "No more outstanding data");
1701 }
1702}
1703
1704void DcSctpSocket::SendShutdown() {
1705 SctpPacket::Builder b = tcb_->PacketBuilder();
1706 b.Add(ShutdownChunk(tcb_->data_tracker().last_cumulative_acked_tsn()));
Victor Boivieabf61882021-08-12 15:57:49 +02001707 packet_sender_.Send(b);
Victor Boivieb6580cc2021-04-08 09:56:59 +02001708}
1709
1710void DcSctpSocket::SendShutdownAck() {
Victor Boivieabf61882021-08-12 15:57:49 +02001711 packet_sender_.Send(tcb_->PacketBuilder().Add(ShutdownAckChunk()));
Victor Boivieb6580cc2021-04-08 09:56:59 +02001712 t2_shutdown_->set_duration(tcb_->current_rto());
1713 t2_shutdown_->Start();
1714}
1715
Sergey Sukhanov43972812021-09-17 15:32:48 +02001716HandoverReadinessStatus DcSctpSocket::GetHandoverReadiness() const {
Victor Boivie5755f3e2021-09-29 22:23:15 +02001717 RTC_DCHECK_RUN_ON(&thread_checker_);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001718 HandoverReadinessStatus status;
1719 if (state_ != State::kClosed && state_ != State::kEstablished) {
1720 status.Add(HandoverUnreadinessReason::kWrongConnectionState);
1721 }
Sergey Sukhanov72435322021-09-21 13:31:09 +02001722 status.Add(send_queue_.GetHandoverReadiness());
Sergey Sukhanov43972812021-09-17 15:32:48 +02001723 if (tcb_) {
1724 status.Add(tcb_->GetHandoverReadiness());
1725 }
1726 return status;
1727}
1728
1729absl::optional<DcSctpSocketHandoverState>
1730DcSctpSocket::GetHandoverStateAndClose() {
Victor Boivie5755f3e2021-09-29 22:23:15 +02001731 RTC_DCHECK_RUN_ON(&thread_checker_);
Victor Boivie15a0c882021-09-28 21:38:34 +02001732 CallbackDeferrer::ScopedDeferrer deferrer(callbacks_);
1733
Sergey Sukhanov43972812021-09-17 15:32:48 +02001734 if (!GetHandoverReadiness().IsReady()) {
1735 return absl::nullopt;
1736 }
1737
1738 DcSctpSocketHandoverState state;
1739
1740 if (state_ == State::kClosed) {
1741 state.socket_state = DcSctpSocketHandoverState::SocketState::kClosed;
1742 } else if (state_ == State::kEstablished) {
1743 state.socket_state = DcSctpSocketHandoverState::SocketState::kConnected;
1744 tcb_->AddHandoverState(state);
Sergey Sukhanov72435322021-09-21 13:31:09 +02001745 send_queue_.AddHandoverState(state);
Sergey Sukhanov43972812021-09-17 15:32:48 +02001746 InternalClose(ErrorKind::kNoError, "handover");
Sergey Sukhanov43972812021-09-17 15:32:48 +02001747 }
1748
1749 return std::move(state);
1750}
1751
Victor Boivieb6580cc2021-04-08 09:56:59 +02001752} // namespace dcsctp