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