Thanks to visit codestin.com
Credit goes to webrtc.googlesource.com

blob: 14f085737a12a16fdfb6a826b6f959d16a35364a [file] [log] [blame]
Harald Alvestrand00cf34c2019-12-02 08:56:021/*
2 * Copyright 2019 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
Harald Alvestrand05e4d082019-12-03 13:04:2111#include "pc/data_channel_controller.h"
12
Harald Alvestrandf0d5caf2025-04-07 09:08:5113#include <cstddef>
Philip Eliasson17ddd312025-04-08 08:33:4914#include <cstdint>
15#include <memory>
Florent Castelli8037fc62024-08-29 13:00:4016#include <optional>
Harald Alvestrandf0d5caf2025-04-07 09:08:5117#include <string>
Harald Alvestrand05e4d082019-12-03 13:04:2118#include <utility>
Harald Alvestrandf0d5caf2025-04-07 09:08:5119#include <vector>
Harald Alvestrand00cf34c2019-12-02 08:56:0220
Tommi51edb562023-03-14 08:23:5121#include "absl/algorithm/container.h"
Jonas Oreland90ea1412025-07-04 11:54:3622#include "absl/functional/any_invocable.h"
Philip Eliasson17ddd312025-04-08 08:33:4923#include "api/array_view.h"
24#include "api/data_channel_event_observer_interface.h"
Harald Alvestrandf0d5caf2025-04-07 09:08:5125#include "api/data_channel_interface.h"
Florent Castelli0012bfa2024-07-26 16:16:4126#include "api/priority.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0827#include "api/rtc_error.h"
Harald Alvestrandf0d5caf2025-04-07 09:08:5128#include "api/scoped_refptr.h"
29#include "api/sequence_checker.h"
30#include "api/task_queue/pending_task_safety_flag.h"
31#include "api/transport/data_channel_transport_interface.h"
32#include "media/sctp/sctp_transport_internal.h"
33#include "pc/data_channel_utils.h"
Harald Alvestrand5b84f382022-02-08 10:49:0934#include "pc/peer_connection_internal.h"
Harald Alvestrandf0d5caf2025-04-07 09:08:5135#include "pc/sctp_data_channel.h"
Harald Alvestrand00cf34c2019-12-02 08:56:0236#include "pc/sctp_utils.h"
Harald Alvestrandf0d5caf2025-04-07 09:08:5137#include "rtc_base/checks.h"
38#include "rtc_base/copy_on_write_buffer.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0839#include "rtc_base/logging.h"
Harald Alvestrandf0d5caf2025-04-07 09:08:5140#include "rtc_base/ssl_stream_adapter.h"
41#include "rtc_base/thread.h"
Philip Eliasson17ddd312025-04-08 08:33:4942#include "rtc_base/time_utils.h"
Harald Alvestrand00cf34c2019-12-02 08:56:0243
44namespace webrtc {
45
Philip Eliasson17ddd312025-04-08 08:33:4946using Message = DataChannelEventObserverInterface::Message;
47using Direction = DataChannelEventObserverInterface::Message::Direction;
48
Tommi4f7ade52023-03-29 18:46:5949DataChannelController::~DataChannelController() {
Tommi52719652023-04-04 09:59:5550 RTC_DCHECK(sctp_data_channels_n_.empty())
51 << "Missing call to TeardownDataChannelTransport_n?";
52 RTC_DCHECK(!signaling_safety_.flag()->alive())
53 << "Missing call to PrepareForShutdown?";
Tommi4f7ade52023-03-29 18:46:5954}
Harald Alvestrand9e5aeb92022-05-11 09:35:3655
Philipp Hancke522380f2023-05-09 07:41:0356bool DataChannelController::HasDataChannels() const {
Tommi44ebe2a2023-05-15 13:14:1057 RTC_DCHECK_RUN_ON(signaling_thread());
58 return channel_usage_ == DataChannelUsage::kInUse;
Harald Alvestrand05e4d082019-12-03 13:04:2159}
60
Harald Alvestrand5da3eb02023-03-15 20:39:4261bool DataChannelController::HasUsedDataChannels() const {
62 RTC_DCHECK_RUN_ON(signaling_thread());
Tommi44ebe2a2023-05-15 13:14:1063 return channel_usage_ != DataChannelUsage::kNeverUsed;
Harald Alvestrand5da3eb02023-03-15 20:39:4264}
65
Philip Eliasson17ddd312025-04-08 08:33:4966void DataChannelController::SetEventObserver(
67 std::unique_ptr<DataChannelEventObserverInterface> observer) {
68 RTC_DCHECK_RUN_ON(network_thread());
69 event_observer_ = std::move(observer);
70}
71
Evan Shrubsolee6a1f702025-04-15 14:55:4272RTCError DataChannelController::SendData(StreamId sid,
73 const SendDataParams& params,
74 const CopyOnWriteBuffer& payload) {
Tommiadd7ac02023-04-12 10:01:1075 RTC_DCHECK_RUN_ON(network_thread());
76 if (!data_channel_transport_) {
77 RTC_LOG(LS_ERROR) << "SendData called before transport is ready";
78 return RTCError(RTCErrorType::INVALID_STATE);
79 }
Philip Eliasson17ddd312025-04-08 08:33:4980 RTCError result =
81 data_channel_transport_->SendData(sid.stream_id_int(), params, payload);
82
83 if (event_observer_ && result.ok()) {
84 if (std::optional<Message> message =
85 BuildObserverMessage(sid, params.type, payload, Direction::kSend)) {
86 event_observer_->OnMessage(*message);
87 }
88 }
89
90 return result;
Harald Alvestrand00cf34c2019-12-02 08:56:0291}
92
Florent Castelli0012bfa2024-07-26 16:16:4193void DataChannelController::AddSctpDataStream(StreamId sid,
94 PriorityValue priority) {
Tommi55f72802023-03-27 10:39:3395 RTC_DCHECK_RUN_ON(network_thread());
Tommiadd7ac02023-04-12 10:01:1096 if (data_channel_transport_) {
Florent Castelli0012bfa2024-07-26 16:16:4197 data_channel_transport_->OpenChannel(sid.stream_id_int(), priority);
Harald Alvestrand00cf34c2019-12-02 08:56:0298 }
99}
100
Tommi4c842222023-03-21 10:35:24101void DataChannelController::RemoveSctpDataStream(StreamId sid) {
Tommi55f72802023-03-27 10:39:33102 RTC_DCHECK_RUN_ON(network_thread());
Tommiadd7ac02023-04-12 10:01:10103 if (data_channel_transport_) {
104 data_channel_transport_->CloseChannel(sid.stream_id_int());
Harald Alvestrand00cf34c2019-12-02 08:56:02105 }
106}
107
Tommid2afbaf2023-03-02 09:51:16108void DataChannelController::OnChannelStateChanged(
109 SctpDataChannel* channel,
110 DataChannelInterface::DataState state) {
Tommif9e13f82023-04-06 19:21:45111 RTC_DCHECK_RUN_ON(network_thread());
Tommieec18102023-06-22 08:13:52112
113 // Stash away the internal id here in case `OnSctpDataChannelClosed` ends up
114 // releasing the last reference to the channel.
115 const int channel_id = channel->internal_id();
116
Tommid2afbaf2023-03-02 09:51:16117 if (state == DataChannelInterface::DataState::kClosed)
118 OnSctpDataChannelClosed(channel);
119
Tommi44ebe2a2023-05-15 13:14:10120 DataChannelUsage channel_usage = sctp_data_channels_n_.empty()
121 ? DataChannelUsage::kHaveBeenUsed
122 : DataChannelUsage::kInUse;
123 signaling_thread()->PostTask(SafeTask(
Tommieec18102023-06-22 08:13:52124 signaling_safety_.flag(), [this, channel_id, state, channel_usage] {
Tommi44ebe2a2023-05-15 13:14:10125 RTC_DCHECK_RUN_ON(signaling_thread());
126 channel_usage_ = channel_usage;
127 pc_->OnSctpDataChannelStateChanged(channel_id, state);
128 }));
Tommid2afbaf2023-03-02 09:51:16129}
130
Victor Boiviefea41f52024-03-11 15:43:31131size_t DataChannelController::buffered_amount(StreamId sid) const {
132 RTC_DCHECK_RUN_ON(network_thread());
133 if (!data_channel_transport_) {
134 return 0;
135 }
136 return data_channel_transport_->buffered_amount(sid.stream_id_int());
137}
138
Victor Boiviecdecc4e2024-03-18 12:47:34139size_t DataChannelController::buffered_amount_low_threshold(
140 StreamId sid) const {
141 RTC_DCHECK_RUN_ON(network_thread());
142 if (!data_channel_transport_) {
143 return 0;
144 }
145 return data_channel_transport_->buffered_amount_low_threshold(
146 sid.stream_id_int());
147}
148
149void DataChannelController::SetBufferedAmountLowThreshold(StreamId sid,
150 size_t bytes) {
151 RTC_DCHECK_RUN_ON(network_thread());
152 if (!data_channel_transport_) {
153 return;
154 }
155 data_channel_transport_->SetBufferedAmountLowThreshold(sid.stream_id_int(),
156 bytes);
157}
158
Evan Shrubsolee6a1f702025-04-15 14:55:42159void DataChannelController::OnDataReceived(int channel_id,
160 DataMessageType type,
161 const CopyOnWriteBuffer& buffer) {
Harald Alvestrand00cf34c2019-12-02 08:56:02162 RTC_DCHECK_RUN_ON(network_thread());
Tommi5bbfb002023-03-04 15:47:53163
Tommi4e1c9572023-03-15 11:36:20164 if (HandleOpenMessage_n(channel_id, type, buffer))
Tommi5bbfb002023-03-04 15:47:53165 return;
166
Tommif9e13f82023-04-06 19:21:45167 auto it = absl::c_find_if(sctp_data_channels_n_, [&](const auto& c) {
Victor Boiviecd3d29b2024-03-09 20:50:42168 return c->sid_n().has_value() && c->sid_n()->stream_id_int() == channel_id;
Tommif9e13f82023-04-06 19:21:45169 });
170
Philip Eliasson17ddd312025-04-08 08:33:49171 if (it != sctp_data_channels_n_.end()) {
Tommif9e13f82023-04-06 19:21:45172 (*it)->OnDataReceived(type, buffer);
Philip Eliasson17ddd312025-04-08 08:33:49173
174 if (event_observer_) {
175 if (std::optional<Message> message = BuildObserverMessage(
176 StreamId(channel_id), type, buffer, Direction::kReceive)) {
177 event_observer_->OnMessage(*message);
178 }
179 }
180 }
Harald Alvestrand00cf34c2019-12-02 08:56:02181}
182
Harald Alvestrand05e4d082019-12-03 13:04:21183void DataChannelController::OnChannelClosing(int channel_id) {
Harald Alvestrand00cf34c2019-12-02 08:56:02184 RTC_DCHECK_RUN_ON(network_thread());
Tommif9e13f82023-04-06 19:21:45185 auto it = absl::c_find_if(sctp_data_channels_n_, [&](const auto& c) {
Victor Boiviecd3d29b2024-03-09 20:50:42186 return c->sid_n().has_value() && c->sid_n()->stream_id_int() == channel_id;
Tommif9e13f82023-04-06 19:21:45187 });
188
189 if (it != sctp_data_channels_n_.end())
190 (*it)->OnClosingProcedureStartedRemotely();
Harald Alvestrand00cf34c2019-12-02 08:56:02191}
192
Harald Alvestrand05e4d082019-12-03 13:04:21193void DataChannelController::OnChannelClosed(int channel_id) {
Harald Alvestrand00cf34c2019-12-02 08:56:02194 RTC_DCHECK_RUN_ON(network_thread());
Tommi4f7ade52023-03-29 18:46:59195 StreamId sid(channel_id);
196 sid_allocator_.ReleaseSid(sid);
197 auto it = absl::c_find_if(sctp_data_channels_n_,
Tommi1158bde2023-03-30 10:01:56198 [&](const auto& c) { return c->sid_n() == sid; });
Tommi51edb562023-03-14 08:23:51199
Tommif9e13f82023-04-06 19:21:45200 if (it != sctp_data_channels_n_.end()) {
Evan Shrubsolee6a1f702025-04-15 14:55:42201 scoped_refptr<SctpDataChannel> channel = std::move(*it);
Tommi4f7ade52023-03-29 18:46:59202 sctp_data_channels_n_.erase(it);
Tommif9e13f82023-04-06 19:21:45203 channel->OnClosingProcedureComplete();
204 }
Harald Alvestrand00cf34c2019-12-02 08:56:02205}
206
Harald Alvestrand05e4d082019-12-03 13:04:21207void DataChannelController::OnReadyToSend() {
Harald Alvestrand00cf34c2019-12-02 08:56:02208 RTC_DCHECK_RUN_ON(network_thread());
Tommif9e13f82023-04-06 19:21:45209 auto copy = sctp_data_channels_n_;
210 for (const auto& channel : copy) {
Victor Boiviecd3d29b2024-03-09 20:50:42211 if (channel->sid_n().has_value()) {
Tommie9aa8672023-03-20 13:43:09212 channel->OnTransportReady();
Tommif9e13f82023-04-06 19:21:45213 } else {
214 // This happens for role==SSL_SERVER channels when we get notified by
215 // the transport *before* the SDP code calls `AllocateSctpSids` to
216 // trigger assignment of sids. In this case OnTransportReady() will be
217 // called from within `AllocateSctpSids` below.
218 RTC_LOG(LS_INFO) << "OnReadyToSend: Still waiting for an id for channel.";
219 }
220 }
Harald Alvestrand00cf34c2019-12-02 08:56:02221}
222
Florent Castellidcb9ffc2021-06-29 12:58:23223void DataChannelController::OnTransportClosed(RTCError error) {
Harald Alvestrand2697ac12019-12-16 09:37:04224 RTC_DCHECK_RUN_ON(network_thread());
Tommib00d63c2023-04-12 17:49:53225
Tommif9e13f82023-04-06 19:21:45226 // This loop will close all data channels and trigger a callback to
Tommib00d63c2023-04-12 17:49:53227 // `OnSctpDataChannelClosed`. We'll empty `sctp_data_channels_n_`, first
228 // and `OnSctpDataChannelClosed` will become a noop but we'll release the
229 // StreamId here.
Evan Shrubsolee6a1f702025-04-15 14:55:42230 std::vector<scoped_refptr<SctpDataChannel>> temp_sctp_dcs;
Tommib00d63c2023-04-12 17:49:53231 temp_sctp_dcs.swap(sctp_data_channels_n_);
232 for (const auto& channel : temp_sctp_dcs) {
Tommif9e13f82023-04-06 19:21:45233 channel->OnTransportChannelClosed(error);
Victor Boiviecd3d29b2024-03-09 20:50:42234 if (channel->sid_n().has_value()) {
235 sid_allocator_.ReleaseSid(*channel->sid_n());
236 }
Tommib00d63c2023-04-12 17:49:53237 }
Harald Alvestrand2697ac12019-12-16 09:37:04238}
239
Victor Boiviecdecc4e2024-03-18 12:47:34240void DataChannelController::OnBufferedAmountLow(int channel_id) {
241 RTC_DCHECK_RUN_ON(network_thread());
242 auto it = absl::c_find_if(sctp_data_channels_n_, [&](const auto& c) {
243 return c->sid_n().has_value() && c->sid_n()->stream_id_int() == channel_id;
244 });
245
246 if (it != sctp_data_channels_n_.end())
247 (*it)->OnBufferedAmountLow();
248}
249
Tommiaa3c9f22023-04-18 10:19:19250void DataChannelController::SetupDataChannelTransport_n(
251 DataChannelTransportInterface* transport) {
Harald Alvestrand00cf34c2019-12-02 08:56:02252 RTC_DCHECK_RUN_ON(network_thread());
Tommiaa3c9f22023-04-18 10:19:19253 RTC_DCHECK(transport);
254 set_data_channel_transport(transport);
Harald Alvestrand00cf34c2019-12-02 08:56:02255}
256
Tommi1f708ef2023-03-31 16:40:50257void DataChannelController::PrepareForShutdown() {
258 RTC_DCHECK_RUN_ON(signaling_thread());
Tommi52719652023-04-04 09:59:55259 signaling_safety_.reset(PendingTaskSafetyFlag::CreateDetachedInactive());
Tommi44ebe2a2023-05-15 13:14:10260 if (channel_usage_ != DataChannelUsage::kNeverUsed)
261 channel_usage_ = DataChannelUsage::kHaveBeenUsed;
Tommi1f708ef2023-03-31 16:40:50262}
263
Tommib00d63c2023-04-12 17:49:53264void DataChannelController::TeardownDataChannelTransport_n(RTCError error) {
Harald Alvestrand00cf34c2019-12-02 08:56:02265 RTC_DCHECK_RUN_ON(network_thread());
Mirko Bonadei29831352023-04-14 17:03:47266 OnTransportClosed(error);
Tommiaa3c9f22023-04-18 10:19:19267 set_data_channel_transport(nullptr);
Tommib00d63c2023-04-12 17:49:53268 RTC_DCHECK(sctp_data_channels_n_.empty());
Tommif9e13f82023-04-06 19:21:45269 weak_factory_.InvalidateWeakPtrs();
Harald Alvestrand00cf34c2019-12-02 08:56:02270}
271
Harald Alvestrand05e4d082019-12-03 13:04:21272void DataChannelController::OnTransportChanged(
Harald Alvestrand00cf34c2019-12-02 08:56:02273 DataChannelTransportInterface* new_data_channel_transport) {
274 RTC_DCHECK_RUN_ON(network_thread());
Tommiadd7ac02023-04-12 10:01:10275 if (data_channel_transport_ &&
276 data_channel_transport_ != new_data_channel_transport) {
Artem Titov880fa812021-07-30 20:30:23277 // Changed which data channel transport is used for `sctp_mid_` (eg. now
Harald Alvestrand00cf34c2019-12-02 08:56:02278 // it's bundled).
Harald Alvestrand00cf34c2019-12-02 08:56:02279 set_data_channel_transport(new_data_channel_transport);
Harald Alvestrand00cf34c2019-12-02 08:56:02280 }
281}
282
Taylor Brandstetter3a034e12020-07-09 22:32:34283std::vector<DataChannelStats> DataChannelController::GetDataChannelStats()
Tomas Gunnarsson2e94de52020-06-16 14:54:10284 const {
Tommif9e13f82023-04-06 19:21:45285 RTC_DCHECK_RUN_ON(network_thread());
Taylor Brandstetter3a034e12020-07-09 22:32:34286 std::vector<DataChannelStats> stats;
Tommif9e13f82023-04-06 19:21:45287 stats.reserve(sctp_data_channels_n_.size());
288 for (const auto& channel : sctp_data_channels_n_)
Tomas Gunnarsson2e94de52020-06-16 14:54:10289 stats.push_back(channel->GetStats());
290 return stats;
291}
292
Tommi5bbfb002023-03-04 15:47:53293bool DataChannelController::HandleOpenMessage_n(
Tommi4e1c9572023-03-15 11:36:20294 int channel_id,
295 DataMessageType type,
Evan Shrubsolee6a1f702025-04-15 14:55:42296 const CopyOnWriteBuffer& buffer) {
Tommi4e1c9572023-03-15 11:36:20297 if (type != DataMessageType::kControl || !IsOpenMessage(buffer))
Tommi5bbfb002023-03-04 15:47:53298 return false;
299
300 // Received OPEN message; parse and signal that a new data channel should
301 // be created.
302 std::string label;
303 InternalDataChannelInit config;
Tommi4e1c9572023-03-15 11:36:20304 config.id = channel_id;
Tommi5bbfb002023-03-04 15:47:53305 if (!ParseDataChannelOpenMessage(buffer, &label, &config)) {
306 RTC_LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
Tommi4e1c9572023-03-15 11:36:20307 << channel_id;
Tommi5bbfb002023-03-04 15:47:53308 } else {
Harald Alvestrand00cf34c2019-12-02 08:56:02309 config.open_handshake_role = InternalDataChannelInit::kAcker;
Tommif9e13f82023-04-06 19:21:45310 auto channel_or_error = CreateDataChannel(label, config);
311 if (channel_or_error.ok()) {
312 signaling_thread()->PostTask(SafeTask(
313 signaling_safety_.flag(),
314 [this, channel = channel_or_error.MoveValue(),
315 ready_to_send = data_channel_transport_->IsReadyToSend()] {
316 RTC_DCHECK_RUN_ON(signaling_thread());
317 OnDataChannelOpenMessage(std::move(channel), ready_to_send);
318 }));
319 } else {
320 RTC_LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message."
321 << ToString(channel_or_error.error().type());
322 }
Harald Alvestrand00cf34c2019-12-02 08:56:02323 }
Tommi5bbfb002023-03-04 15:47:53324 return true;
Harald Alvestrand00cf34c2019-12-02 08:56:02325}
326
Harald Alvestrand05e4d082019-12-03 13:04:21327void DataChannelController::OnDataChannelOpenMessage(
Evan Shrubsolee6a1f702025-04-15 14:55:42328 scoped_refptr<SctpDataChannel> channel,
Tommif9e13f82023-04-06 19:21:45329 bool ready_to_send) {
Tommi44ebe2a2023-05-15 13:14:10330 channel_usage_ = DataChannelUsage::kInUse;
Tommif9e13f82023-04-06 19:21:45331 auto proxy = SctpDataChannel::CreateProxy(channel, signaling_safety_.flag());
Andrey Logvin7f16fcd2023-04-05 08:53:13332
Jonas Oreland90ea1412025-07-04 11:54:36333 pc_->RunWithObserver([&](auto observer) { observer->OnDataChannel(proxy); });
Andrey Logvin7f16fcd2023-04-05 08:53:13334 pc_->NoteDataAddedEvent();
Tommif9e13f82023-04-06 19:21:45335
336 if (ready_to_send) {
337 network_thread()->PostTask([channel = std::move(channel)] {
338 if (channel->state() != DataChannelInterface::DataState::kClosed)
339 channel->OnTransportReady();
340 });
341 }
Harald Alvestrand00cf34c2019-12-02 08:56:02342}
343
Tommi4f7ade52023-03-29 18:46:59344// RTC_RUN_ON(network_thread())
345RTCError DataChannelController::ReserveOrAllocateSid(
Florent Castelli8037fc62024-08-29 13:00:40346 std::optional<StreamId>& sid,
Evan Shrubsoleeb835d02025-03-12 09:41:06347 std::optional<SSLRole> fallback_ssl_role) {
Victor Boiviecd3d29b2024-03-09 20:50:42348 if (sid.has_value()) {
349 return sid_allocator_.ReserveSid(*sid)
Tommi4f7ade52023-03-29 18:46:59350 ? RTCError::OK()
Victor Boiviecd3d29b2024-03-09 20:50:42351 : RTCError(RTCErrorType::INVALID_RANGE, "StreamId reserved.");
Tommi4f7ade52023-03-29 18:46:59352 }
353
354 // Attempt to allocate an ID based on the negotiated role.
Evan Shrubsoleeb835d02025-03-12 09:41:06355 std::optional<SSLRole> role = pc_->GetSctpSslRole_n();
Tommi4f7ade52023-03-29 18:46:59356 if (!role)
357 role = fallback_ssl_role;
358 if (role) {
359 sid = sid_allocator_.AllocateSid(*role);
Victor Boiviecd3d29b2024-03-09 20:50:42360 if (!sid.has_value())
Tommi4f7ade52023-03-29 18:46:59361 return RTCError(RTCErrorType::RESOURCE_EXHAUSTED);
362 }
363 // When we get here, we may still not have an ID, but that's a supported case
364 // whereby an id will be assigned later.
Victor Boiviecd3d29b2024-03-09 20:50:42365 RTC_DCHECK(sid.has_value() || !role);
Tommi4f7ade52023-03-29 18:46:59366 return RTCError::OK();
367}
368
Tommif9e13f82023-04-06 19:21:45369// RTC_RUN_ON(network_thread())
Evan Shrubsolee6a1f702025-04-15 14:55:42370RTCErrorOr<scoped_refptr<SctpDataChannel>>
Tommif9e13f82023-04-06 19:21:45371DataChannelController::CreateDataChannel(const std::string& label,
372 InternalDataChannelInit& config) {
Florent Castelli8037fc62024-08-29 13:00:40373 std::optional<StreamId> sid = std::nullopt;
Victor Boiviecd3d29b2024-03-09 20:50:42374 if (config.id != -1) {
Evan Shrubsole945e5172025-04-08 14:11:45375 if (config.id < 0 || config.id > kMaxSctpSid) {
Victor Boiviecd3d29b2024-03-09 20:50:42376 return RTCError(RTCErrorType::INVALID_RANGE, "StreamId out of range.");
377 }
378 sid = StreamId(config.id);
379 }
380
Tommif9e13f82023-04-06 19:21:45381 RTCError err = ReserveOrAllocateSid(sid, config.fallback_ssl_role);
382 if (!err.ok())
383 return err;
384
385 // In case `sid` has changed. Update `config` accordingly.
Victor Boiviecd3d29b2024-03-09 20:50:42386 if (sid.has_value()) {
387 config.id = sid->stream_id_int();
388 }
Tommif9e13f82023-04-06 19:21:45389
Evan Shrubsolee6a1f702025-04-15 14:55:42390 scoped_refptr<SctpDataChannel> channel = SctpDataChannel::Create(
Tommif9e13f82023-04-06 19:21:45391 weak_factory_.GetWeakPtr(), label, data_channel_transport_ != nullptr,
392 config, signaling_thread(), network_thread());
393 RTC_DCHECK(channel);
394 sctp_data_channels_n_.push_back(channel);
395
396 // If we have an id already, notify the transport.
Victor Boiviecd3d29b2024-03-09 20:50:42397 if (sid.has_value())
Florent Castelli0012bfa2024-07-26 16:16:41398 AddSctpDataStream(*sid,
399 config.priority.value_or(PriorityValue(Priority::kLow)));
Tommif9e13f82023-04-06 19:21:45400
401 return channel;
402}
403
Evan Shrubsolee6a1f702025-04-15 14:55:42404RTCErrorOr<scoped_refptr<DataChannelInterface>>
Taylor Brandstetter3a034e12020-07-09 22:32:34405DataChannelController::InternalCreateDataChannelWithProxy(
Harald Alvestrand00cf34c2019-12-02 08:56:02406 const std::string& label,
Tommi335d0842023-03-25 09:56:18407 const InternalDataChannelInit& config) {
Harald Alvestrand05e4d082019-12-03 13:04:21408 RTC_DCHECK_RUN_ON(signaling_thread());
Tommi4f7ade52023-03-29 18:46:59409 RTC_DCHECK(!pc_->IsClosed());
Tommi335d0842023-03-25 09:56:18410 if (!config.IsValid()) {
Tommi4f7ade52023-03-29 18:46:59411 LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_PARAMETER,
412 "Invalid DataChannelInit");
Tommi9296a162023-03-21 15:28:52413 }
414
Tommi4f7ade52023-03-29 18:46:59415 bool ready_to_send = false;
Tommi335d0842023-03-25 09:56:18416 InternalDataChannelInit new_config = config;
Tommi4f7ade52023-03-29 18:46:59417 auto ret = network_thread()->BlockingCall(
Evan Shrubsolee6a1f702025-04-15 14:55:42418 [&]() -> RTCErrorOr<scoped_refptr<SctpDataChannel>> {
Tommi4f7ade52023-03-29 18:46:59419 RTC_DCHECK_RUN_ON(network_thread());
Tommif9e13f82023-04-06 19:21:45420 auto channel = CreateDataChannel(label, new_config);
421 if (!channel.ok())
422 return channel;
Tommi4f7ade52023-03-29 18:46:59423 ready_to_send =
424 data_channel_transport_ && data_channel_transport_->IsReadyToSend();
Tommif9e13f82023-04-06 19:21:45425 if (ready_to_send) {
426 // If the transport is ready to send because the initial channel
427 // ready signal may have been sent before the DataChannel creation.
428 // This has to be done async because the upper layer objects (e.g.
429 // Chrome glue and WebKit) are not wired up properly until after
430 // `InternalCreateDataChannelWithProxy` returns.
431 network_thread()->PostTask([channel = channel.value()] {
432 if (channel->state() != DataChannelInterface::DataState::kClosed)
433 channel->OnTransportReady();
434 });
435 }
Tommi4f7ade52023-03-29 18:46:59436
437 return channel;
438 });
439
440 if (!ret.ok())
441 return ret.MoveError();
442
Tommi44ebe2a2023-05-15 13:14:10443 channel_usage_ = DataChannelUsage::kInUse;
Tommif9e13f82023-04-06 19:21:45444 return SctpDataChannel::CreateProxy(ret.MoveValue(),
445 signaling_safety_.flag());
Harald Alvestrand00cf34c2019-12-02 08:56:02446}
447
Evan Shrubsoleeb835d02025-03-12 09:41:06448void DataChannelController::AllocateSctpSids(SSLRole role) {
Tommif9e13f82023-04-06 19:21:45449 RTC_DCHECK_RUN_ON(network_thread());
450
451 const bool ready_to_send =
452 data_channel_transport_ && data_channel_transport_->IsReadyToSend();
Tommi4f7ade52023-03-29 18:46:59453
454 std::vector<std::pair<SctpDataChannel*, StreamId>> channels_to_update;
Evan Shrubsolee6a1f702025-04-15 14:55:42455 std::vector<scoped_refptr<SctpDataChannel>> channels_to_close;
Tommif9e13f82023-04-06 19:21:45456 for (auto it = sctp_data_channels_n_.begin();
457 it != sctp_data_channels_n_.end();) {
Victor Boiviecd3d29b2024-03-09 20:50:42458 if (!(*it)->sid_n().has_value()) {
Florent Castelli8037fc62024-08-29 13:00:40459 std::optional<StreamId> sid = sid_allocator_.AllocateSid(role);
Victor Boiviecd3d29b2024-03-09 20:50:42460 if (sid.has_value()) {
461 (*it)->SetSctpSid_n(*sid);
Florent Castelli0012bfa2024-07-26 16:16:41462 AddSctpDataStream(*sid, (*it)->priority());
Tommif9e13f82023-04-06 19:21:45463 if (ready_to_send) {
464 RTC_LOG(LS_INFO) << "AllocateSctpSids: Id assigned, ready to send.";
465 (*it)->OnTransportReady();
Tommi4f7ade52023-03-29 18:46:59466 }
Victor Boiviecd3d29b2024-03-09 20:50:42467 channels_to_update.push_back(std::make_pair((*it).get(), *sid));
Tommif9e13f82023-04-06 19:21:45468 } else {
469 channels_to_close.push_back(std::move(*it));
470 it = sctp_data_channels_n_.erase(it);
471 continue;
Harald Alvestrand00cf34c2019-12-02 08:56:02472 }
Harald Alvestrand00cf34c2019-12-02 08:56:02473 }
Tommif9e13f82023-04-06 19:21:45474 ++it;
475 }
Tommi4f7ade52023-03-29 18:46:59476
Harald Alvestrand00cf34c2019-12-02 08:56:02477 // Since closing modifies the list of channels, we have to do the actual
478 // closing outside the loop.
479 for (const auto& channel : channels_to_close) {
Harald Alvestranddfbfb462019-12-08 04:55:43480 channel->CloseAbruptlyWithDataChannelFailure("Failed to allocate SCTP SID");
Harald Alvestrand00cf34c2019-12-02 08:56:02481 }
482}
483
Taylor Brandstetter3a034e12020-07-09 22:32:34484void DataChannelController::OnSctpDataChannelClosed(SctpDataChannel* channel) {
Tommif9e13f82023-04-06 19:21:45485 RTC_DCHECK_RUN_ON(network_thread());
486 // After the closing procedure is done, it's safe to use this ID for
487 // another data channel.
Victor Boiviecd3d29b2024-03-09 20:50:42488 if (channel->sid_n().has_value()) {
489 sid_allocator_.ReleaseSid(*channel->sid_n());
Harald Alvestrand00cf34c2019-12-02 08:56:02490 }
Tommif9e13f82023-04-06 19:21:45491 auto it = absl::c_find_if(sctp_data_channels_n_,
492 [&](const auto& c) { return c.get() == channel; });
493 if (it != sctp_data_channels_n_.end())
494 sctp_data_channels_n_.erase(it);
Harald Alvestrand00cf34c2019-12-02 08:56:02495}
496
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:42497void DataChannelController::set_data_channel_transport(
498 DataChannelTransportInterface* transport) {
499 RTC_DCHECK_RUN_ON(network_thread());
Tommiaa3c9f22023-04-18 10:19:19500
501 if (data_channel_transport_)
502 data_channel_transport_->SetDataSink(nullptr);
503
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:42504 data_channel_transport_ = transport;
Tommiaa3c9f22023-04-18 10:19:19505
506 if (data_channel_transport_) {
507 // There's a new data channel transport. This needs to be signaled to the
508 // `sctp_data_channels_n_` so that they can reopen and reconnect. This is
509 // necessary when bundling is applied.
510 NotifyDataChannelsOfTransportCreated();
511 data_channel_transport_->SetDataSink(this);
512 }
Tomas Gunnarsson7d3cfbf2020-06-15 11:47:42513}
514
Philip Eliasson17ddd312025-04-08 08:33:49515std::optional<Message> DataChannelController::BuildObserverMessage(
516 StreamId sid,
517 DataMessageType type,
518 ArrayView<const uint8_t> payload,
519 Message::Direction direction) const {
520 RTC_DCHECK_RUN_ON(network_thread());
521
522 if (type != DataMessageType::kText && type != DataMessageType::kBinary) {
523 return std::nullopt;
524 }
525
526 auto it = absl::c_find_if(sctp_data_channels_n_, [sid](const auto& channel) {
527 return channel->sid_n() == sid;
528 });
529
530 if (it == sctp_data_channels_n_.end()) {
531 return std::nullopt;
532 }
533
534 Message message;
535 Message::DataType data_type = type == DataMessageType::kBinary
536 ? Message::DataType::kBinary
537 : Message::DataType::kString;
538 message.set_data_type(data_type);
Evan Shrubsolee6a1f702025-04-15 14:55:42539 message.set_unix_timestamp_ms(TimeUTCMillis());
Philip Eliasson17ddd312025-04-08 08:33:49540 message.set_datachannel_id(sid.stream_id_int());
541 message.set_label((*it)->label());
542 message.set_direction(direction);
543 message.set_data(payload);
544
545 return message;
546}
547
Tomas Gunnarsson2e94de52020-06-16 14:54:10548void DataChannelController::NotifyDataChannelsOfTransportCreated() {
549 RTC_DCHECK_RUN_ON(network_thread());
Tommiadd7ac02023-04-12 10:01:10550 RTC_DCHECK(data_channel_transport_);
Tommi4f7ade52023-03-29 18:46:59551
Tommi1158bde2023-03-30 10:01:56552 for (const auto& channel : sctp_data_channels_n_) {
Victor Boiviecd3d29b2024-03-09 20:50:42553 if (channel->sid_n().has_value())
Florent Castelli0012bfa2024-07-26 16:16:41554 AddSctpDataStream(*channel->sid_n(), channel->priority());
Tommif9e13f82023-04-06 19:21:45555 channel->OnTransportChannelCreated();
Tommi1158bde2023-03-30 10:01:56556 }
Tommidc90a9c2023-03-20 09:26:19557}
558
Evan Shrubsole6a9a1ae2025-03-21 12:54:15559Thread* DataChannelController::network_thread() const {
Harald Alvestrand05e4d082019-12-03 13:04:21560 return pc_->network_thread();
561}
Tommif9e13f82023-04-06 19:21:45562
Evan Shrubsole6a9a1ae2025-03-21 12:54:15563Thread* DataChannelController::signaling_thread() const {
Harald Alvestrand05e4d082019-12-03 13:04:21564 return pc_->signaling_thread();
565}
566
Harald Alvestrand00cf34c2019-12-02 08:56:02567} // namespace webrtc