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