blob: 4623435ea97f5fa4e486c18175f447273dd3b075 [file] [log] [blame]
Florent Castellia6983c62021-05-06 08:50:071/*
2 * Copyright 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
11#include "media/sctp/dcsctp_transport.h"
12
Florent Castelli9bbfe9e2022-02-21 13:39:4713#include <atomic>
Florent Castellia6983c62021-05-06 08:50:0714#include <cstdint>
Florent Castelli5183f002021-05-07 11:52:4415#include <limits>
Florent Castellia6983c62021-05-06 08:50:0716#include <utility>
17#include <vector>
18
19#include "absl/strings/string_view.h"
20#include "absl/types/optional.h"
21#include "api/array_view.h"
Victor Boivie2c1cfd02024-03-18 12:51:4022#include "api/data_channel_interface.h"
Victor Boiviecd54fd82024-02-28 11:16:1523#include "api/environment/environment.h"
Florent Castelli0012bfa2024-07-26 16:16:4124#include "api/priority.h"
Florent Castellia6983c62021-05-06 08:50:0725#include "media/base/media_channel.h"
Florent Castelli6a11c842021-06-01 16:39:4926#include "net/dcsctp/public/dcsctp_socket_factory.h"
Victor Boivie61741732021-05-10 15:22:4227#include "net/dcsctp/public/packet_observer.h"
Victor Boivie5e726da2021-06-19 05:59:0128#include "net/dcsctp/public/text_pcap_packet_observer.h"
Florent Castellia6983c62021-05-06 08:50:0729#include "net/dcsctp/public/types.h"
Florent Castellia6983c62021-05-06 08:50:0730#include "p2p/base/packet_transport_internal.h"
31#include "rtc_base/checks.h"
Victor Boivie61741732021-05-10 15:22:4232#include "rtc_base/logging.h"
Per Kf4aadf32024-02-27 08:01:1533#include "rtc_base/network/received_packet.h"
Victor Boivie8df32eb2021-08-12 13:21:2534#include "rtc_base/socket.h"
Victor Boivie61741732021-05-10 15:22:4235#include "rtc_base/strings/string_builder.h"
Florent Castellia6983c62021-05-06 08:50:0736#include "rtc_base/thread.h"
37#include "rtc_base/trace_event.h"
38#include "system_wrappers/include/clock.h"
39
40namespace webrtc {
41
42namespace {
Victor Boivie8df32eb2021-08-12 13:21:2543using ::dcsctp::SendPacketStatus;
Florent Castellia6983c62021-05-06 08:50:0744
Victor Boivief72c0642021-09-20 18:00:5745// When there is packet loss for a long time, the SCTP retry timers will use
46// exponential backoff, which can grow to very long durations and when the
47// connection recovers, it may take a long time to reach the new backoff
48// duration. By limiting it to a reasonable limit, the time to recover reduces.
49constexpr dcsctp::DurationMs kMaxTimerBackoffDuration =
50 dcsctp::DurationMs(3000);
51
Florent Castellia6983c62021-05-06 08:50:0752enum class WebrtcPPID : dcsctp::PPID::UnderlyingType {
Florent Castellia6983c62021-05-06 08:50:0753 // https://www.rfc-editor.org/rfc/rfc8832.html#section-8.1
54 kDCEP = 50,
55 // https://www.rfc-editor.org/rfc/rfc8831.html#section-8
56 kString = 51,
57 kBinaryPartial = 52, // Deprecated
58 kBinary = 53,
59 kStringPartial = 54, // Deprecated
60 kStringEmpty = 56,
61 kBinaryEmpty = 57,
62};
63
Florent Castellid95b1492021-05-10 09:29:5664WebrtcPPID ToPPID(DataMessageType message_type, size_t size) {
Florent Castellia6983c62021-05-06 08:50:0765 switch (message_type) {
Tommi1fabbac2023-03-21 13:48:5166 case DataMessageType::kControl:
Florent Castellia6983c62021-05-06 08:50:0767 return WebrtcPPID::kDCEP;
Tommi1fabbac2023-03-21 13:48:5168 case DataMessageType::kText:
Florent Castellia6983c62021-05-06 08:50:0769 return size > 0 ? WebrtcPPID::kString : WebrtcPPID::kStringEmpty;
Tommi1fabbac2023-03-21 13:48:5170 case DataMessageType::kBinary:
Florent Castellia6983c62021-05-06 08:50:0771 return size > 0 ? WebrtcPPID::kBinary : WebrtcPPID::kBinaryEmpty;
Florent Castellia6983c62021-05-06 08:50:0772 }
Florent Castellia6983c62021-05-06 08:50:0773}
74
Florent Castellid95b1492021-05-10 09:29:5675absl::optional<DataMessageType> ToDataMessageType(dcsctp::PPID ppid) {
Florent Castellia6983c62021-05-06 08:50:0776 switch (static_cast<WebrtcPPID>(ppid.value())) {
Florent Castellia6983c62021-05-06 08:50:0777 case WebrtcPPID::kDCEP:
Tommi1fabbac2023-03-21 13:48:5178 return DataMessageType::kControl;
Florent Castellia6983c62021-05-06 08:50:0779 case WebrtcPPID::kString:
80 case WebrtcPPID::kStringPartial:
81 case WebrtcPPID::kStringEmpty:
Tommi1fabbac2023-03-21 13:48:5182 return DataMessageType::kText;
Florent Castellia6983c62021-05-06 08:50:0783 case WebrtcPPID::kBinary:
84 case WebrtcPPID::kBinaryPartial:
85 case WebrtcPPID::kBinaryEmpty:
Tommi1fabbac2023-03-21 13:48:5186 return DataMessageType::kBinary;
Florent Castellia6983c62021-05-06 08:50:0787 }
88 return absl::nullopt;
89}
90
Florent Castellidcb9ffc2021-06-29 12:58:2391absl::optional<cricket::SctpErrorCauseCode> ToErrorCauseCode(
92 dcsctp::ErrorKind error) {
93 switch (error) {
94 case dcsctp::ErrorKind::kParseFailed:
95 return cricket::SctpErrorCauseCode::kUnrecognizedParameters;
96 case dcsctp::ErrorKind::kPeerReported:
97 return cricket::SctpErrorCauseCode::kUserInitiatedAbort;
98 case dcsctp::ErrorKind::kWrongSequence:
99 case dcsctp::ErrorKind::kProtocolViolation:
100 return cricket::SctpErrorCauseCode::kProtocolViolation;
101 case dcsctp::ErrorKind::kResourceExhaustion:
102 return cricket::SctpErrorCauseCode::kOutOfResource;
103 case dcsctp::ErrorKind::kTooManyRetries:
104 case dcsctp::ErrorKind::kUnsupportedOperation:
105 case dcsctp::ErrorKind::kNoError:
106 case dcsctp::ErrorKind::kNotConnected:
107 // No SCTP error cause code matches those
108 break;
109 }
110 return absl::nullopt;
111}
112
Florent Castellia6983c62021-05-06 08:50:07113bool IsEmptyPPID(dcsctp::PPID ppid) {
114 WebrtcPPID webrtc_ppid = static_cast<WebrtcPPID>(ppid.value());
115 return webrtc_ppid == WebrtcPPID::kStringEmpty ||
116 webrtc_ppid == WebrtcPPID::kBinaryEmpty;
117}
Florent Castellia6983c62021-05-06 08:50:07118} // namespace
119
Victor Boiviecd54fd82024-02-28 11:16:15120DcSctpTransport::DcSctpTransport(const Environment& env,
121 rtc::Thread* network_thread,
122 rtc::PacketTransportInternal* transport)
123 : DcSctpTransport(env,
124 network_thread,
Florent Castellie3b74f82022-05-02 22:24:15125 transport,
Florent Castellie3b74f82022-05-02 22:24:15126 std::make_unique<dcsctp::DcSctpSocketFactory>()) {}
Florent Castellie3b74f82022-05-02 22:24:15127DcSctpTransport::DcSctpTransport(
Victor Boiviecd54fd82024-02-28 11:16:15128 const Environment& env,
Florent Castellie3b74f82022-05-02 22:24:15129 rtc::Thread* network_thread,
130 rtc::PacketTransportInternal* transport,
Florent Castellie3b74f82022-05-02 22:24:15131 std::unique_ptr<dcsctp::DcSctpSocketFactory> socket_factory)
Florent Castellia6983c62021-05-06 08:50:07132 : network_thread_(network_thread),
133 transport_(transport),
Victor Boiviecd54fd82024-02-28 11:16:15134 env_(env),
135 random_(env_.clock().TimeInMicroseconds()),
Florent Castellie3b74f82022-05-02 22:24:15136 socket_factory_(std::move(socket_factory)),
Florent Castellia6983c62021-05-06 08:50:07137 task_queue_timeout_factory_(
138 *network_thread,
139 [this]() { return TimeMillis(); },
140 [this](dcsctp::TimeoutID timeout_id) {
141 socket_->HandleTimeout(timeout_id);
142 }) {
143 RTC_DCHECK_RUN_ON(network_thread_);
Florent Castelli9bbfe9e2022-02-21 13:39:47144 static std::atomic<int> instance_count = 0;
Florent Castellia6983c62021-05-06 08:50:07145 rtc::StringBuilder sb;
146 sb << debug_name_ << instance_count++;
147 debug_name_ = sb.Release();
148 ConnectTransportSignals();
149}
150
151DcSctpTransport::~DcSctpTransport() {
152 if (socket_) {
153 socket_->Close();
154 }
155}
156
Fredrik Solenberg5cb3a902022-08-22 09:34:29157void DcSctpTransport::SetOnConnectedCallback(std::function<void()> callback) {
158 RTC_DCHECK_RUN_ON(network_thread_);
159 on_connected_callback_ = std::move(callback);
160}
161
162void DcSctpTransport::SetDataChannelSink(DataChannelSink* sink) {
163 RTC_DCHECK_RUN_ON(network_thread_);
164 data_channel_sink_ = sink;
165 if (data_channel_sink_ && ready_to_send_data_) {
166 data_channel_sink_->OnReadyToSend();
167 }
168}
169
Florent Castellia6983c62021-05-06 08:50:07170void DcSctpTransport::SetDtlsTransport(
171 rtc::PacketTransportInternal* transport) {
172 RTC_DCHECK_RUN_ON(network_thread_);
173 DisconnectTransportSignals();
174 transport_ = transport;
175 ConnectTransportSignals();
176 MaybeConnectSocket();
177}
178
179bool DcSctpTransport::Start(int local_sctp_port,
180 int remote_sctp_port,
181 int max_message_size) {
182 RTC_DCHECK_RUN_ON(network_thread_);
183 RTC_DCHECK(max_message_size > 0);
Fredrik Solenberg5cb3a902022-08-22 09:34:29184 RTC_DLOG(LS_INFO) << debug_name_ << "->Start(local=" << local_sctp_port
185 << ", remote=" << remote_sctp_port
186 << ", max_message_size=" << max_message_size << ")";
Florent Castellia6983c62021-05-06 08:50:07187
188 if (!socket_) {
189 dcsctp::DcSctpOptions options;
190 options.local_port = local_sctp_port;
191 options.remote_port = remote_sctp_port;
192 options.max_message_size = max_message_size;
Victor Boivief72c0642021-09-20 18:00:57193 options.max_timer_backoff_duration = kMaxTimerBackoffDuration;
194 // Don't close the connection automatically on too many retransmissions.
195 options.max_retransmissions = absl::nullopt;
196 options.max_init_retransmits = absl::nullopt;
Victor Boivie2c1cfd02024-03-18 12:51:40197 options.per_stream_send_queue_limit =
198 DataChannelInterface::MaxSendQueueSize();
199 // This is just set to avoid denial-of-service. Practically unlimited.
200 options.max_send_buffer_size = std::numeric_limits<size_t>::max();
Victor Boivieb0a1d8b2024-06-12 10:17:22201 options.enable_message_interleaving =
202 env_.field_trials().IsEnabled("WebRTC-DataChannelMessageInterleaving");
Florent Castellia6983c62021-05-06 08:50:07203
Victor Boivie61741732021-05-10 15:22:42204 std::unique_ptr<dcsctp::PacketObserver> packet_observer;
205 if (RTC_LOG_CHECK_LEVEL(LS_VERBOSE)) {
Victor Boivie5e726da2021-06-19 05:59:01206 packet_observer =
207 std::make_unique<dcsctp::TextPcapPacketObserver>(debug_name_);
Victor Boivie61741732021-05-10 15:22:42208 }
209
Florent Castellie3b74f82022-05-02 22:24:15210 socket_ = socket_factory_->Create(debug_name_, *this,
211 std::move(packet_observer), options);
Florent Castellia6983c62021-05-06 08:50:07212 } else {
213 if (local_sctp_port != socket_->options().local_port ||
214 remote_sctp_port != socket_->options().remote_port) {
215 RTC_LOG(LS_ERROR)
216 << debug_name_ << "->Start(local=" << local_sctp_port
217 << ", remote=" << remote_sctp_port
218 << "): Can't change ports on already started transport.";
219 return false;
220 }
221 socket_->SetMaxMessageSize(max_message_size);
222 }
223
224 MaybeConnectSocket();
225
Florent Castelli0012bfa2024-07-26 16:16:41226 for (const auto& [sid, stream_state] : stream_states_) {
227 socket_->SetStreamPriority(sid, stream_state.priority);
228 }
229
Florent Castellia6983c62021-05-06 08:50:07230 return true;
231}
232
Florent Castelli0012bfa2024-07-26 16:16:41233bool DcSctpTransport::OpenStream(int sid, PriorityValue priority) {
Florent Castellidbc2ba22022-08-22 17:46:39234 RTC_DCHECK_RUN_ON(network_thread_);
Florent Castelli0012bfa2024-07-26 16:16:41235 RTC_DLOG(LS_INFO) << debug_name_ << "->OpenStream(" << sid << ", "
236 << priority.value() << ").";
Florent Castellidbc2ba22022-08-22 17:46:39237
238 StreamState stream_state;
Florent Castelli0012bfa2024-07-26 16:16:41239 stream_state.priority = dcsctp::StreamPriority(priority.value());
Florent Castellidbc2ba22022-08-22 17:46:39240 stream_states_.insert_or_assign(dcsctp::StreamID(static_cast<uint16_t>(sid)),
241 stream_state);
Florent Castelli0012bfa2024-07-26 16:16:41242 if (socket_) {
243 socket_->SetStreamPriority(dcsctp::StreamID(sid),
244 dcsctp::StreamPriority(priority.value()));
245 }
246
Florent Castellia6983c62021-05-06 08:50:07247 return true;
248}
249
250bool DcSctpTransport::ResetStream(int sid) {
Florent Castellidbc2ba22022-08-22 17:46:39251 RTC_DCHECK_RUN_ON(network_thread_);
Fredrik Solenberg5cb3a902022-08-22 09:34:29252 RTC_DLOG(LS_INFO) << debug_name_ << "->ResetStream(" << sid << ").";
Florent Castellia6983c62021-05-06 08:50:07253 if (!socket_) {
Florent Castelli8f04c7c2022-05-05 21:43:44254 RTC_LOG(LS_ERROR) << debug_name_ << "->ResetStream(sid=" << sid
Florent Castellia6983c62021-05-06 08:50:07255 << "): Transport is not started.";
256 return false;
257 }
Florent Castelli8f04c7c2022-05-05 21:43:44258
Florent Castellia6983c62021-05-06 08:50:07259 dcsctp::StreamID streams[1] = {dcsctp::StreamID(static_cast<uint16_t>(sid))};
Florent Castelli8f04c7c2022-05-05 21:43:44260
Florent Castellidbc2ba22022-08-22 17:46:39261 auto it = stream_states_.find(streams[0]);
262 if (it == stream_states_.end()) {
263 RTC_LOG(LS_ERROR) << debug_name_ << "->ResetStream(sid=" << sid
264 << "): Stream is not open.";
265 return false;
266 }
267
268 StreamState& stream_state = it->second;
269 if (stream_state.closure_initiated || stream_state.incoming_reset_done ||
270 stream_state.outgoing_reset_done) {
Florent Castelli8f04c7c2022-05-05 21:43:44271 // The closing procedure was already initiated by the remote, don't do
272 // anything.
273 return false;
274 }
Florent Castellidbc2ba22022-08-22 17:46:39275 stream_state.closure_initiated = true;
Florent Castellia6983c62021-05-06 08:50:07276 socket_->ResetStreams(streams);
277 return true;
278}
279
Tommi1fabbac2023-03-21 13:48:51280RTCError DcSctpTransport::SendData(int sid,
281 const SendDataParams& params,
282 const rtc::CopyOnWriteBuffer& payload) {
Florent Castellia6983c62021-05-06 08:50:07283 RTC_DCHECK_RUN_ON(network_thread_);
Fredrik Solenberg5cb3a902022-08-22 09:34:29284 RTC_DLOG(LS_VERBOSE) << debug_name_ << "->SendData(sid=" << sid
285 << ", type=" << static_cast<int>(params.type)
286 << ", length=" << payload.size() << ").";
Florent Castellia6983c62021-05-06 08:50:07287
288 if (!socket_) {
289 RTC_LOG(LS_ERROR) << debug_name_
290 << "->SendData(...): Transport is not started.";
Tommi1fabbac2023-03-21 13:48:51291 return RTCError(RTCErrorType::INVALID_STATE);
Florent Castellia6983c62021-05-06 08:50:07292 }
293
Florent Castellidbc2ba22022-08-22 17:46:39294 // It is possible for a message to be sent from the signaling thread at the
295 // same time a data-channel is closing, but before the signaling thread is
296 // aware of it. So we need to keep track of currently active data channels and
297 // skip sending messages for the ones that are not open or closing.
298 // The sending errors are not impacting the data channel API contract as
299 // it is allowed to discard queued messages when the channel is closing.
300 auto stream_state =
301 stream_states_.find(dcsctp::StreamID(static_cast<uint16_t>(sid)));
302 if (stream_state == stream_states_.end()) {
303 RTC_LOG(LS_VERBOSE) << "Skipping message on non-open stream with sid: "
304 << sid;
Tommi1fabbac2023-03-21 13:48:51305 return RTCError(RTCErrorType::INVALID_STATE);
Florent Castellidbc2ba22022-08-22 17:46:39306 }
307
308 if (stream_state->second.closure_initiated ||
309 stream_state->second.incoming_reset_done ||
310 stream_state->second.outgoing_reset_done) {
311 RTC_LOG(LS_VERBOSE) << "Skipping message on closing stream with sid: "
312 << sid;
Tommi1fabbac2023-03-21 13:48:51313 return RTCError(RTCErrorType::INVALID_STATE);
Florent Castellidbc2ba22022-08-22 17:46:39314 }
315
Florent Castellia6983c62021-05-06 08:50:07316 auto max_message_size = socket_->options().max_message_size;
317 if (max_message_size > 0 && payload.size() > max_message_size) {
Victor Boivie402ceff2021-05-19 12:26:22318 RTC_LOG(LS_WARNING) << debug_name_
319 << "->SendData(...): "
320 "Trying to send packet bigger "
321 "than the max message size: "
322 << payload.size() << " vs max of " << max_message_size;
Tommi1fabbac2023-03-21 13:48:51323 return RTCError(RTCErrorType::INVALID_RANGE);
Florent Castellia6983c62021-05-06 08:50:07324 }
325
326 std::vector<uint8_t> message_payload(payload.cdata(),
327 payload.cdata() + payload.size());
328 if (message_payload.empty()) {
329 // https://www.rfc-editor.org/rfc/rfc8831.html#section-6.6
330 // SCTP does not support the sending of empty user messages. Therefore, if
331 // an empty message has to be sent, the appropriate PPID (WebRTC String
332 // Empty or WebRTC Binary Empty) is used, and the SCTP user message of one
333 // zero byte is sent.
334 message_payload.push_back('\0');
335 }
336
337 dcsctp::DcSctpMessage message(
Florent Castellid95b1492021-05-10 09:29:56338 dcsctp::StreamID(static_cast<uint16_t>(sid)),
Florent Castellia6983c62021-05-06 08:50:07339 dcsctp::PPID(static_cast<uint16_t>(ToPPID(params.type, payload.size()))),
340 std::move(message_payload));
341
342 dcsctp::SendOptions send_options;
343 send_options.unordered = dcsctp::IsUnordered(!params.ordered);
Florent Castelli5183f002021-05-07 11:52:44344 if (params.max_rtx_ms.has_value()) {
345 RTC_DCHECK(*params.max_rtx_ms >= 0 &&
346 *params.max_rtx_ms <= std::numeric_limits<uint16_t>::max());
347 send_options.lifetime = dcsctp::DurationMs(*params.max_rtx_ms);
348 }
349 if (params.max_rtx_count.has_value()) {
350 RTC_DCHECK(*params.max_rtx_count >= 0 &&
351 *params.max_rtx_count <= std::numeric_limits<uint16_t>::max());
352 send_options.max_retransmissions = *params.max_rtx_count;
353 }
Florent Castellia6983c62021-05-06 08:50:07354
Tommi1fabbac2023-03-21 13:48:51355 dcsctp::SendStatus error = socket_->Send(std::move(message), send_options);
Florent Castellia6983c62021-05-06 08:50:07356 switch (error) {
357 case dcsctp::SendStatus::kSuccess:
Tommi1fabbac2023-03-21 13:48:51358 return RTCError::OK();
Florent Castellia6983c62021-05-06 08:50:07359 case dcsctp::SendStatus::kErrorResourceExhaustion:
Florent Castellia6983c62021-05-06 08:50:07360 ready_to_send_data_ = false;
Tommi1fabbac2023-03-21 13:48:51361 return RTCError(RTCErrorType::RESOURCE_EXHAUSTED);
Florent Castellia6983c62021-05-06 08:50:07362 default:
Tommi1fabbac2023-03-21 13:48:51363 absl::string_view message = dcsctp::ToString(error);
Florent Castellia6983c62021-05-06 08:50:07364 RTC_LOG(LS_ERROR) << debug_name_
365 << "->SendData(...): send() failed with error "
Tommi1fabbac2023-03-21 13:48:51366 << message << ".";
367 return RTCError(RTCErrorType::NETWORK_ERROR, message);
Florent Castellia6983c62021-05-06 08:50:07368 }
Florent Castellia6983c62021-05-06 08:50:07369}
370
371bool DcSctpTransport::ReadyToSendData() {
Tommi72b12a92023-03-21 19:29:16372 RTC_DCHECK_RUN_ON(network_thread_);
Florent Castellia6983c62021-05-06 08:50:07373 return ready_to_send_data_;
374}
375
376int DcSctpTransport::max_message_size() const {
377 if (!socket_) {
378 RTC_LOG(LS_ERROR) << debug_name_
379 << "->max_message_size(...): Transport is not started.";
380 return 0;
381 }
382 return socket_->options().max_message_size;
383}
384
385absl::optional<int> DcSctpTransport::max_outbound_streams() const {
386 if (!socket_)
387 return absl::nullopt;
388 return socket_->options().announced_maximum_outgoing_streams;
389}
390
391absl::optional<int> DcSctpTransport::max_inbound_streams() const {
392 if (!socket_)
393 return absl::nullopt;
394 return socket_->options().announced_maximum_incoming_streams;
395}
396
Victor Boiviefea41f52024-03-11 15:43:31397size_t DcSctpTransport::buffered_amount(int sid) const {
398 if (!socket_)
399 return 0;
400 return socket_->buffered_amount(dcsctp::StreamID(sid));
401}
402
Victor Boiviecdecc4e2024-03-18 12:47:34403size_t DcSctpTransport::buffered_amount_low_threshold(int sid) const {
404 if (!socket_)
405 return 0;
406 return socket_->buffered_amount_low_threshold(dcsctp::StreamID(sid));
407}
408
409void DcSctpTransport::SetBufferedAmountLowThreshold(int sid, size_t bytes) {
410 if (!socket_)
411 return;
412 socket_->SetBufferedAmountLowThreshold(dcsctp::StreamID(sid), bytes);
413}
414
Florent Castellia6983c62021-05-06 08:50:07415void DcSctpTransport::set_debug_name_for_testing(const char* debug_name) {
416 debug_name_ = debug_name;
417}
418
Victor Boivie8df32eb2021-08-12 13:21:25419SendPacketStatus DcSctpTransport::SendPacketWithStatus(
420 rtc::ArrayView<const uint8_t> data) {
Florent Castellia6983c62021-05-06 08:50:07421 RTC_DCHECK_RUN_ON(network_thread_);
422 RTC_DCHECK(socket_);
423
424 if (data.size() > (socket_->options().mtu)) {
425 RTC_LOG(LS_ERROR) << debug_name_
426 << "->SendPacket(...): "
427 "SCTP seems to have made a packet that is bigger "
428 "than its official MTU: "
429 << data.size() << " vs max of " << socket_->options().mtu;
Victor Boivie8df32eb2021-08-12 13:21:25430 return SendPacketStatus::kError;
Florent Castellia6983c62021-05-06 08:50:07431 }
432 TRACE_EVENT0("webrtc", "DcSctpTransport::SendPacket");
433
434 if (!transport_ || !transport_->writable())
Victor Boivie8df32eb2021-08-12 13:21:25435 return SendPacketStatus::kError;
Florent Castellia6983c62021-05-06 08:50:07436
Victor Boivie767235d2021-09-06 10:10:14437 RTC_DLOG(LS_VERBOSE) << debug_name_ << "->SendPacket(length=" << data.size()
438 << ")";
Florent Castellia6983c62021-05-06 08:50:07439
440 auto result =
441 transport_->SendPacket(reinterpret_cast<const char*>(data.data()),
442 data.size(), rtc::PacketOptions(), 0);
443
444 if (result < 0) {
Victor Boivie402ceff2021-05-19 12:26:22445 RTC_LOG(LS_WARNING) << debug_name_ << "->SendPacket(length=" << data.size()
446 << ") failed with error: " << transport_->GetError()
447 << ".";
Victor Boivie8df32eb2021-08-12 13:21:25448
449 if (rtc::IsBlockingError(transport_->GetError())) {
450 return SendPacketStatus::kTemporaryFailure;
451 }
452 return SendPacketStatus::kError;
Florent Castellia6983c62021-05-06 08:50:07453 }
Victor Boivie8df32eb2021-08-12 13:21:25454 return SendPacketStatus::kSuccess;
Florent Castellia6983c62021-05-06 08:50:07455}
456
Henrik Boströmb951dc62022-01-26 17:38:13457std::unique_ptr<dcsctp::Timeout> DcSctpTransport::CreateTimeout(
Tommi1fabbac2023-03-21 13:48:51458 TaskQueueBase::DelayPrecision precision) {
Henrik Boströmb951dc62022-01-26 17:38:13459 return task_queue_timeout_factory_.CreateTimeout(precision);
Florent Castellia6983c62021-05-06 08:50:07460}
461
462dcsctp::TimeMs DcSctpTransport::TimeMillis() {
Victor Boiviecd54fd82024-02-28 11:16:15463 return dcsctp::TimeMs(env_.clock().TimeInMilliseconds());
Florent Castellia6983c62021-05-06 08:50:07464}
465
466uint32_t DcSctpTransport::GetRandomInt(uint32_t low, uint32_t high) {
467 return random_.Rand(low, high);
468}
469
Victor Boivie236ac502021-05-20 17:34:18470void DcSctpTransport::OnTotalBufferedAmountLow() {
Fredrik Solenberg5cb3a902022-08-22 09:34:29471 RTC_DCHECK_RUN_ON(network_thread_);
Florent Castellia6983c62021-05-06 08:50:07472 if (!ready_to_send_data_) {
473 ready_to_send_data_ = true;
Fredrik Solenberg5cb3a902022-08-22 09:34:29474 if (data_channel_sink_) {
475 data_channel_sink_->OnReadyToSend();
476 }
Florent Castellia6983c62021-05-06 08:50:07477 }
478}
479
Victor Boiviecdecc4e2024-03-18 12:47:34480void DcSctpTransport::OnBufferedAmountLow(dcsctp::StreamID stream_id) {
481 RTC_DCHECK_RUN_ON(network_thread_);
482 if (data_channel_sink_) {
483 data_channel_sink_->OnBufferedAmountLow(*stream_id);
484 }
485}
486
Florent Castellia6983c62021-05-06 08:50:07487void DcSctpTransport::OnMessageReceived(dcsctp::DcSctpMessage message) {
488 RTC_DCHECK_RUN_ON(network_thread_);
Fredrik Solenberg5cb3a902022-08-22 09:34:29489 RTC_DLOG(LS_VERBOSE) << debug_name_ << "->OnMessageReceived(sid="
490 << message.stream_id().value()
491 << ", ppid=" << message.ppid().value()
492 << ", length=" << message.payload().size() << ").";
Florent Castellia6983c62021-05-06 08:50:07493 auto type = ToDataMessageType(message.ppid());
494 if (!type.has_value()) {
495 RTC_LOG(LS_VERBOSE) << debug_name_
496 << "->OnMessageReceived(): Received an unknown PPID "
497 << message.ppid().value()
498 << " on an SCTP packet. Dropping.";
Florent Castelli691d4a02023-03-13 14:17:17499 return;
Florent Castellia6983c62021-05-06 08:50:07500 }
Florent Castellia6983c62021-05-06 08:50:07501 receive_buffer_.Clear();
502 if (!IsEmptyPPID(message.ppid()))
503 receive_buffer_.AppendData(message.payload().data(),
504 message.payload().size());
505
Fredrik Solenberg5cb3a902022-08-22 09:34:29506 if (data_channel_sink_) {
Tommi4e1c9572023-03-15 11:36:20507 data_channel_sink_->OnDataReceived(message.stream_id().value(), *type,
508 receive_buffer_);
Fredrik Solenberg5cb3a902022-08-22 09:34:29509 }
Florent Castellia6983c62021-05-06 08:50:07510}
511
512void DcSctpTransport::OnError(dcsctp::ErrorKind error,
513 absl::string_view message) {
Victor Boivie8ae1adc2021-10-14 08:38:23514 if (error == dcsctp::ErrorKind::kResourceExhaustion) {
515 // Indicates that a message failed to be enqueued, because the send buffer
516 // is full, which is a very common (and wanted) state for high throughput
517 // sending/benchmarks.
518 RTC_LOG(LS_VERBOSE) << debug_name_
519 << "->OnError(error=" << dcsctp::ToString(error)
520 << ", message=" << message << ").";
521 } else {
522 RTC_LOG(LS_ERROR) << debug_name_
523 << "->OnError(error=" << dcsctp::ToString(error)
524 << ", message=" << message << ").";
525 }
Florent Castellia6983c62021-05-06 08:50:07526}
527
528void DcSctpTransport::OnAborted(dcsctp::ErrorKind error,
529 absl::string_view message) {
Fredrik Solenberg5cb3a902022-08-22 09:34:29530 RTC_DCHECK_RUN_ON(network_thread_);
Florent Castellia6983c62021-05-06 08:50:07531 RTC_LOG(LS_ERROR) << debug_name_
532 << "->OnAborted(error=" << dcsctp::ToString(error)
533 << ", message=" << message << ").";
534 ready_to_send_data_ = false;
Florent Castellidcb9ffc2021-06-29 12:58:23535 RTCError rtc_error(RTCErrorType::OPERATION_ERROR_WITH_DATA,
536 std::string(message));
537 rtc_error.set_error_detail(RTCErrorDetailType::SCTP_FAILURE);
538 auto code = ToErrorCauseCode(error);
539 if (code.has_value()) {
540 rtc_error.set_sctp_cause_code(static_cast<uint16_t>(*code));
541 }
Fredrik Solenberg5cb3a902022-08-22 09:34:29542 if (data_channel_sink_) {
543 data_channel_sink_->OnTransportClosed(rtc_error);
544 }
Florent Castellia6983c62021-05-06 08:50:07545}
546
547void DcSctpTransport::OnConnected() {
Fredrik Solenberg5cb3a902022-08-22 09:34:29548 RTC_DCHECK_RUN_ON(network_thread_);
549 RTC_DLOG(LS_INFO) << debug_name_ << "->OnConnected().";
Florent Castellia6983c62021-05-06 08:50:07550 ready_to_send_data_ = true;
Fredrik Solenberg5cb3a902022-08-22 09:34:29551 if (data_channel_sink_) {
552 data_channel_sink_->OnReadyToSend();
553 }
554 if (on_connected_callback_) {
555 on_connected_callback_();
556 }
Florent Castellia6983c62021-05-06 08:50:07557}
558
559void DcSctpTransport::OnClosed() {
Tommi72b12a92023-03-21 19:29:16560 RTC_DCHECK_RUN_ON(network_thread_);
Fredrik Solenberg5cb3a902022-08-22 09:34:29561 RTC_DLOG(LS_INFO) << debug_name_ << "->OnClosed().";
Florent Castellia6983c62021-05-06 08:50:07562 ready_to_send_data_ = false;
563}
564
565void DcSctpTransport::OnConnectionRestarted() {
Fredrik Solenberg5cb3a902022-08-22 09:34:29566 RTC_DLOG(LS_INFO) << debug_name_ << "->OnConnectionRestarted().";
Florent Castellia6983c62021-05-06 08:50:07567}
568
569void DcSctpTransport::OnStreamsResetFailed(
570 rtc::ArrayView<const dcsctp::StreamID> outgoing_streams,
571 absl::string_view reason) {
572 // TODO(orphis): Need a test to check for correct behavior
573 for (auto& stream_id : outgoing_streams) {
Victor Boivie402ceff2021-05-19 12:26:22574 RTC_LOG(LS_WARNING)
Florent Castellia6983c62021-05-06 08:50:07575 << debug_name_
576 << "->OnStreamsResetFailed(...): Outgoing stream reset failed"
577 << ", sid=" << stream_id.value() << ", reason: " << reason << ".";
578 }
579}
580
581void DcSctpTransport::OnStreamsResetPerformed(
582 rtc::ArrayView<const dcsctp::StreamID> outgoing_streams) {
Fredrik Solenberg5cb3a902022-08-22 09:34:29583 RTC_DCHECK_RUN_ON(network_thread_);
Florent Castellia6983c62021-05-06 08:50:07584 for (auto& stream_id : outgoing_streams) {
585 RTC_LOG(LS_INFO) << debug_name_
586 << "->OnStreamsResetPerformed(...): Outgoing stream reset"
587 << ", sid=" << stream_id.value();
Florent Castelli8f04c7c2022-05-05 21:43:44588
Florent Castellidbc2ba22022-08-22 17:46:39589 auto it = stream_states_.find(stream_id);
590 if (it == stream_states_.end()) {
591 // Ignoring an outgoing stream reset for a closed stream
592 return;
593 }
594
595 StreamState& stream_state = it->second;
596 stream_state.outgoing_reset_done = true;
597
598 if (stream_state.incoming_reset_done) {
Florent Castelli8f04c7c2022-05-05 21:43:44599 // When the close was not initiated locally, we can signal the end of the
600 // data channel close procedure when the remote ACKs the reset.
Fredrik Solenberg5cb3a902022-08-22 09:34:29601 if (data_channel_sink_) {
602 data_channel_sink_->OnChannelClosed(stream_id.value());
603 }
Florent Castellidbc2ba22022-08-22 17:46:39604 stream_states_.erase(stream_id);
Florent Castellie3b74f82022-05-02 22:24:15605 }
Florent Castellia6983c62021-05-06 08:50:07606 }
607}
608
609void DcSctpTransport::OnIncomingStreamsReset(
610 rtc::ArrayView<const dcsctp::StreamID> incoming_streams) {
Fredrik Solenberg5cb3a902022-08-22 09:34:29611 RTC_DCHECK_RUN_ON(network_thread_);
Florent Castellia6983c62021-05-06 08:50:07612 for (auto& stream_id : incoming_streams) {
613 RTC_LOG(LS_INFO) << debug_name_
614 << "->OnIncomingStreamsReset(...): Incoming stream reset"
615 << ", sid=" << stream_id.value();
Florent Castelli8f04c7c2022-05-05 21:43:44616
Florent Castellidbc2ba22022-08-22 17:46:39617 auto it = stream_states_.find(stream_id);
618 if (it == stream_states_.end())
619 return;
620
621 StreamState& stream_state = it->second;
622 stream_state.incoming_reset_done = true;
623
624 if (!stream_state.closure_initiated) {
Florent Castellie3b74f82022-05-02 22:24:15625 // When receiving an incoming stream reset event for a non local close
626 // procedure, the transport needs to reset the stream in the other
627 // direction too.
628 dcsctp::StreamID streams[1] = {stream_id};
629 socket_->ResetStreams(streams);
Fredrik Solenberg5cb3a902022-08-22 09:34:29630 if (data_channel_sink_) {
631 data_channel_sink_->OnChannelClosing(stream_id.value());
632 }
Florent Castelli8f04c7c2022-05-05 21:43:44633 }
634
Florent Castellidbc2ba22022-08-22 17:46:39635 if (stream_state.outgoing_reset_done) {
Florent Castellie3b74f82022-05-02 22:24:15636 // The close procedure that was initiated locally is complete when we
637 // receive and incoming reset event.
Fredrik Solenberg5cb3a902022-08-22 09:34:29638 if (data_channel_sink_) {
639 data_channel_sink_->OnChannelClosed(stream_id.value());
640 }
Florent Castellidbc2ba22022-08-22 17:46:39641 stream_states_.erase(stream_id);
Florent Castellie3b74f82022-05-02 22:24:15642 }
Florent Castellia6983c62021-05-06 08:50:07643 }
644}
645
646void DcSctpTransport::ConnectTransportSignals() {
647 RTC_DCHECK_RUN_ON(network_thread_);
648 if (!transport_) {
649 return;
650 }
651 transport_->SignalWritableState.connect(
652 this, &DcSctpTransport::OnTransportWritableState);
Per Kf4aadf32024-02-27 08:01:15653 transport_->RegisterReceivedPacketCallback(
654 this, [&](rtc::PacketTransportInternal* transport,
655 const rtc::ReceivedPacket& packet) {
656 OnTransportReadPacket(transport, packet);
657 });
Tommi1d26fd32024-03-18 16:57:52658 transport_->SetOnCloseCallback([this]() {
659 RTC_DCHECK_RUN_ON(network_thread_);
660 RTC_DLOG(LS_VERBOSE) << debug_name_ << "->OnTransportClosed().";
661 if (data_channel_sink_) {
662 data_channel_sink_->OnTransportClosed({});
663 }
664 });
Florent Castellia6983c62021-05-06 08:50:07665}
666
667void DcSctpTransport::DisconnectTransportSignals() {
668 RTC_DCHECK_RUN_ON(network_thread_);
669 if (!transport_) {
670 return;
671 }
672 transport_->SignalWritableState.disconnect(this);
Per Kf4aadf32024-02-27 08:01:15673 transport_->DeregisterReceivedPacketCallback(this);
Tommi1d26fd32024-03-18 16:57:52674 transport_->SetOnCloseCallback(nullptr);
Florent Castellia6983c62021-05-06 08:50:07675}
676
677void DcSctpTransport::OnTransportWritableState(
678 rtc::PacketTransportInternal* transport) {
679 RTC_DCHECK_RUN_ON(network_thread_);
680 RTC_DCHECK_EQ(transport_, transport);
Fredrik Solenberg5cb3a902022-08-22 09:34:29681 RTC_DLOG(LS_VERBOSE) << debug_name_
682 << "->OnTransportWritableState(), writable="
683 << transport->writable();
Florent Castellia6983c62021-05-06 08:50:07684 MaybeConnectSocket();
685}
686
687void DcSctpTransport::OnTransportReadPacket(
688 rtc::PacketTransportInternal* transport,
Per Kf4aadf32024-02-27 08:01:15689 const rtc::ReceivedPacket& packet) {
Philipp Hancke8e64e2d2022-01-10 21:32:58690 RTC_DCHECK_RUN_ON(network_thread_);
Per Kf4aadf32024-02-27 08:01:15691 if (packet.decryption_info() != rtc::ReceivedPacket::kDtlsDecrypted) {
Florent Castellia6983c62021-05-06 08:50:07692 // We are only interested in SCTP packets.
693 return;
694 }
695
Per Kf4aadf32024-02-27 08:01:15696 RTC_DLOG(LS_VERBOSE) << debug_name_ << "->OnTransportReadPacket(), length="
697 << packet.payload().size();
Florent Castellia6983c62021-05-06 08:50:07698 if (socket_) {
Per Kf4aadf32024-02-27 08:01:15699 socket_->ReceivePacket(packet.payload());
Florent Castellia6983c62021-05-06 08:50:07700 }
701}
702
Florent Castellia6983c62021-05-06 08:50:07703void DcSctpTransport::MaybeConnectSocket() {
704 if (transport_ && transport_->writable() && socket_ &&
705 socket_->state() == dcsctp::SocketState::kClosed) {
706 socket_->Connect();
707 }
708}
709} // namespace webrtc