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