blob: 6b3500cbff2d508cae950cbf5eac643e22e3d083 [file] [log] [blame]
Harald Alvestrand00cf34c2019-12-02 09:56:02 +01001/*
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 14:04:21 +010011#include "pc/data_channel_controller.h"
12
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000013#include <algorithm>
Harald Alvestrand05e4d082019-12-03 14:04:21 +010014#include <utility>
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010015
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000016#include "absl/algorithm/container.h"
17#include "absl/types/optional.h"
18#include "api/peer_connection_interface.h"
19#include "api/rtc_error.h"
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010020#include "pc/peer_connection.h"
21#include "pc/sctp_utils.h"
Harald Alvestrand5761e7b2021-01-29 14:45:08 +000022#include "rtc_base/location.h"
23#include "rtc_base/logging.h"
24#include "rtc_base/string_encode.h"
Niels Möller236e36c2021-03-23 09:23:10 +010025#include "rtc_base/task_utils/to_queued_task.h"
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010026
27namespace webrtc {
28
Harald Alvestrand05e4d082019-12-03 14:04:21 +010029bool DataChannelController::HasDataChannels() const {
30 RTC_DCHECK_RUN_ON(signaling_thread());
Harald Alvestrand7af57c62021-04-16 11:12:14 +000031 return !sctp_data_channels_.empty();
Harald Alvestrand05e4d082019-12-03 14:04:21 +010032}
33
34bool DataChannelController::SendData(const cricket::SendDataParams& params,
35 const rtc::CopyOnWriteBuffer& payload,
36 cricket::SendDataResult* result) {
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +020037 if (data_channel_transport())
38 return DataChannelSendData(params, payload, result);
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010039 RTC_LOG(LS_ERROR) << "SendData called before transport is ready";
40 return false;
41}
42
Harald Alvestrand05e4d082019-12-03 14:04:21 +010043bool DataChannelController::ConnectDataChannel(
Taylor Brandstetter3a034e12020-07-09 15:32:34 -070044 SctpDataChannel* webrtc_data_channel) {
45 RTC_DCHECK_RUN_ON(signaling_thread());
46 if (!data_channel_transport()) {
47 // Don't log an error here, because DataChannels are expected to call
48 // ConnectDataChannel in this state. It's the only way to initially tell
49 // whether or not the underlying transport is ready.
50 return false;
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010051 }
Taylor Brandstetter3a034e12020-07-09 15:32:34 -070052 SignalDataChannelTransportWritable_s.connect(
53 webrtc_data_channel, &SctpDataChannel::OnTransportReady);
54 SignalDataChannelTransportReceivedData_s.connect(
55 webrtc_data_channel, &SctpDataChannel::OnDataReceived);
56 SignalDataChannelTransportChannelClosing_s.connect(
57 webrtc_data_channel, &SctpDataChannel::OnClosingProcedureStartedRemotely);
58 SignalDataChannelTransportChannelClosed_s.connect(
59 webrtc_data_channel, &SctpDataChannel::OnClosingProcedureComplete);
60 return true;
61}
62
63void DataChannelController::DisconnectDataChannel(
64 SctpDataChannel* webrtc_data_channel) {
65 RTC_DCHECK_RUN_ON(signaling_thread());
66 if (!data_channel_transport()) {
67 RTC_LOG(LS_ERROR)
68 << "DisconnectDataChannel called when sctp_transport_ is NULL.";
69 return;
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010070 }
Taylor Brandstetter3a034e12020-07-09 15:32:34 -070071 SignalDataChannelTransportWritable_s.disconnect(webrtc_data_channel);
72 SignalDataChannelTransportReceivedData_s.disconnect(webrtc_data_channel);
73 SignalDataChannelTransportChannelClosing_s.disconnect(webrtc_data_channel);
74 SignalDataChannelTransportChannelClosed_s.disconnect(webrtc_data_channel);
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010075}
76
Harald Alvestrand05e4d082019-12-03 14:04:21 +010077void DataChannelController::AddSctpDataStream(int sid) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010078 if (data_channel_transport()) {
79 network_thread()->Invoke<void>(RTC_FROM_HERE, [this, sid] {
80 if (data_channel_transport()) {
81 data_channel_transport()->OpenChannel(sid);
82 }
83 });
84 }
85}
86
Harald Alvestrand05e4d082019-12-03 14:04:21 +010087void DataChannelController::RemoveSctpDataStream(int sid) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010088 if (data_channel_transport()) {
89 network_thread()->Invoke<void>(RTC_FROM_HERE, [this, sid] {
90 if (data_channel_transport()) {
91 data_channel_transport()->CloseChannel(sid);
92 }
93 });
94 }
95}
96
Harald Alvestrand05e4d082019-12-03 14:04:21 +010097bool DataChannelController::ReadyToSendData() const {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010098 RTC_DCHECK_RUN_ON(signaling_thread());
Harald Alvestrand7af57c62021-04-16 11:12:14 +000099 return (data_channel_transport() && data_channel_transport_ready_to_send_);
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100100}
101
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100102void DataChannelController::OnDataReceived(
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100103 int channel_id,
104 DataMessageType type,
105 const rtc::CopyOnWriteBuffer& buffer) {
106 RTC_DCHECK_RUN_ON(network_thread());
107 cricket::ReceiveDataParams params;
108 params.sid = channel_id;
109 params.type = ToCricketDataMessageType(type);
Niels Möller236e36c2021-03-23 09:23:10 +0100110 signaling_thread()->PostTask(
111 ToQueuedTask([self = weak_factory_.GetWeakPtr(), params, buffer] {
112 if (self) {
113 RTC_DCHECK_RUN_ON(self->signaling_thread());
114 // TODO(bugs.webrtc.org/11547): The data being received should be
115 // delivered on the network thread. The way HandleOpenMessage_s works
116 // right now is that it's called for all types of buffers and operates
117 // as a selector function. Change this so that it's only called for
118 // buffers that it should be able to handle. Once we do that, we can
119 // deliver all other buffers on the network thread (change
120 // SignalDataChannelTransportReceivedData_s to
121 // SignalDataChannelTransportReceivedData_n).
122 if (!self->HandleOpenMessage_s(params, buffer)) {
123 self->SignalDataChannelTransportReceivedData_s(params, buffer);
124 }
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100125 }
Niels Möller236e36c2021-03-23 09:23:10 +0100126 }));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100127}
128
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100129void DataChannelController::OnChannelClosing(int channel_id) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100130 RTC_DCHECK_RUN_ON(network_thread());
Niels Möller236e36c2021-03-23 09:23:10 +0100131 signaling_thread()->PostTask(
132 ToQueuedTask([self = weak_factory_.GetWeakPtr(), channel_id] {
133 if (self) {
134 RTC_DCHECK_RUN_ON(self->signaling_thread());
135 self->SignalDataChannelTransportChannelClosing_s(channel_id);
136 }
137 }));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100138}
139
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100140void DataChannelController::OnChannelClosed(int channel_id) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100141 RTC_DCHECK_RUN_ON(network_thread());
Niels Möller236e36c2021-03-23 09:23:10 +0100142 signaling_thread()->PostTask(
143 ToQueuedTask([self = weak_factory_.GetWeakPtr(), channel_id] {
144 if (self) {
145 RTC_DCHECK_RUN_ON(self->signaling_thread());
146 self->SignalDataChannelTransportChannelClosed_s(channel_id);
147 }
148 }));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100149}
150
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100151void DataChannelController::OnReadyToSend() {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100152 RTC_DCHECK_RUN_ON(network_thread());
Niels Möller236e36c2021-03-23 09:23:10 +0100153 signaling_thread()->PostTask(
154 ToQueuedTask([self = weak_factory_.GetWeakPtr()] {
155 if (self) {
156 RTC_DCHECK_RUN_ON(self->signaling_thread());
157 self->data_channel_transport_ready_to_send_ = true;
158 self->SignalDataChannelTransportWritable_s(
159 self->data_channel_transport_ready_to_send_);
160 }
161 }));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100162}
163
Harald Alvestrand2697ac12019-12-16 10:37:04 +0100164void DataChannelController::OnTransportClosed() {
165 RTC_DCHECK_RUN_ON(network_thread());
Niels Möller236e36c2021-03-23 09:23:10 +0100166 signaling_thread()->PostTask(
167 ToQueuedTask([self = weak_factory_.GetWeakPtr()] {
168 if (self) {
169 RTC_DCHECK_RUN_ON(self->signaling_thread());
170 self->OnTransportChannelClosed();
171 }
172 }));
Harald Alvestrand2697ac12019-12-16 10:37:04 +0100173}
174
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100175void DataChannelController::SetupDataChannelTransport_n() {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100176 RTC_DCHECK_RUN_ON(network_thread());
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200177
178 // There's a new data channel transport. This needs to be signaled to the
179 // |sctp_data_channels_| so that they can reopen and reconnect. This is
180 // necessary when bundling is applied.
181 NotifyDataChannelsOfTransportCreated();
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100182}
183
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100184void DataChannelController::TeardownDataChannelTransport_n() {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100185 RTC_DCHECK_RUN_ON(network_thread());
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100186 if (data_channel_transport()) {
187 data_channel_transport()->SetDataSink(nullptr);
188 }
189 set_data_channel_transport(nullptr);
190}
191
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100192void DataChannelController::OnTransportChanged(
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100193 DataChannelTransportInterface* new_data_channel_transport) {
194 RTC_DCHECK_RUN_ON(network_thread());
195 if (data_channel_transport() &&
196 data_channel_transport() != new_data_channel_transport) {
197 // Changed which data channel transport is used for |sctp_mid_| (eg. now
198 // it's bundled).
199 data_channel_transport()->SetDataSink(nullptr);
200 set_data_channel_transport(new_data_channel_transport);
201 if (new_data_channel_transport) {
202 new_data_channel_transport->SetDataSink(this);
203
204 // There's a new data channel transport. This needs to be signaled to the
205 // |sctp_data_channels_| so that they can reopen and reconnect. This is
206 // necessary when bundling is applied.
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200207 NotifyDataChannelsOfTransportCreated();
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100208 }
209 }
210}
211
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700212std::vector<DataChannelStats> DataChannelController::GetDataChannelStats()
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200213 const {
214 RTC_DCHECK_RUN_ON(signaling_thread());
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700215 std::vector<DataChannelStats> stats;
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200216 stats.reserve(sctp_data_channels_.size());
217 for (const auto& channel : sctp_data_channels_)
218 stats.push_back(channel->GetStats());
219 return stats;
220}
221
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100222bool DataChannelController::HandleOpenMessage_s(
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100223 const cricket::ReceiveDataParams& params,
224 const rtc::CopyOnWriteBuffer& buffer) {
225 if (params.type == cricket::DMT_CONTROL && IsOpenMessage(buffer)) {
226 // Received OPEN message; parse and signal that a new data channel should
227 // be created.
228 std::string label;
229 InternalDataChannelInit config;
Harald Alvestrand7af57c62021-04-16 11:12:14 +0000230 config.id = params.sid;
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100231 if (!ParseDataChannelOpenMessage(buffer, &label, &config)) {
Harald Alvestrand7af57c62021-04-16 11:12:14 +0000232 RTC_LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
233 << params.sid;
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100234 return true;
235 }
236 config.open_handshake_role = InternalDataChannelInit::kAcker;
237 OnDataChannelOpenMessage(label, config);
238 return true;
239 }
240 return false;
241}
242
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100243void DataChannelController::OnDataChannelOpenMessage(
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100244 const std::string& label,
245 const InternalDataChannelInit& config) {
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700246 rtc::scoped_refptr<DataChannelInterface> channel(
247 InternalCreateDataChannelWithProxy(label, &config));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100248 if (!channel.get()) {
249 RTC_LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
250 return;
251 }
252
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700253 pc_->Observer()->OnDataChannel(std::move(channel));
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100254 pc_->NoteDataAddedEvent();
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100255}
256
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700257rtc::scoped_refptr<DataChannelInterface>
258DataChannelController::InternalCreateDataChannelWithProxy(
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100259 const std::string& label,
260 const InternalDataChannelInit* config) {
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100261 RTC_DCHECK_RUN_ON(signaling_thread());
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100262 if (pc_->IsClosed()) {
263 return nullptr;
264 }
Florent Castelli516e2842021-04-19 15:29:50 +0200265
266 rtc::scoped_refptr<SctpDataChannel> channel =
267 InternalCreateSctpDataChannel(label, config);
268 if (channel) {
269 return SctpDataChannel::CreateProxy(channel);
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100270 }
271
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700272 return nullptr;
273}
274
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700275rtc::scoped_refptr<SctpDataChannel>
276DataChannelController::InternalCreateSctpDataChannel(
277 const std::string& label,
278 const InternalDataChannelInit* config) {
279 RTC_DCHECK_RUN_ON(signaling_thread());
280 InternalDataChannelInit new_config =
281 config ? (*config) : InternalDataChannelInit();
282 if (new_config.id < 0) {
283 rtc::SSLRole role;
284 if ((pc_->GetSctpSslRole(&role)) &&
285 !sid_allocator_.AllocateSid(role, &new_config.id)) {
286 RTC_LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
287 return nullptr;
288 }
289 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
290 RTC_LOG(LS_ERROR) << "Failed to create a SCTP data channel "
291 "because the id is already in use or out of range.";
292 return nullptr;
293 }
294 rtc::scoped_refptr<SctpDataChannel> channel(SctpDataChannel::Create(
295 this, label, new_config, signaling_thread(), network_thread()));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100296 if (!channel) {
297 sid_allocator_.ReleaseSid(new_config.id);
298 return nullptr;
299 }
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700300 sctp_data_channels_.push_back(channel);
301 channel->SignalClosed.connect(pc_, &PeerConnection::OnSctpDataChannelClosed);
302 SignalSctpDataChannelCreated_(channel.get());
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100303 return channel;
304}
305
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100306void DataChannelController::AllocateSctpSids(rtc::SSLRole role) {
307 RTC_DCHECK_RUN_ON(signaling_thread());
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700308 std::vector<rtc::scoped_refptr<SctpDataChannel>> channels_to_close;
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100309 for (const auto& channel : sctp_data_channels_) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100310 if (channel->id() < 0) {
311 int sid;
312 if (!sid_allocator_.AllocateSid(role, &sid)) {
313 RTC_LOG(LS_ERROR) << "Failed to allocate SCTP sid, closing channel.";
314 channels_to_close.push_back(channel);
315 continue;
316 }
317 channel->SetSctpSid(sid);
318 }
319 }
320 // Since closing modifies the list of channels, we have to do the actual
321 // closing outside the loop.
322 for (const auto& channel : channels_to_close) {
Harald Alvestranddfbfb462019-12-08 05:55:43 +0100323 channel->CloseAbruptlyWithDataChannelFailure("Failed to allocate SCTP SID");
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100324 }
325}
326
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700327void DataChannelController::OnSctpDataChannelClosed(SctpDataChannel* channel) {
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100328 RTC_DCHECK_RUN_ON(signaling_thread());
329 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
330 ++it) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100331 if (it->get() == channel) {
332 if (channel->id() >= 0) {
333 // After the closing procedure is done, it's safe to use this ID for
334 // another data channel.
335 sid_allocator_.ReleaseSid(channel->id());
336 }
337 // Since this method is triggered by a signal from the DataChannel,
338 // we can't free it directly here; we need to free it asynchronously.
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100339 sctp_data_channels_to_free_.push_back(*it);
340 sctp_data_channels_.erase(it);
Harald Alvestrand246724b2019-12-03 22:31:42 +0100341 signaling_thread()->PostTask(
Niels Möller236e36c2021-03-23 09:23:10 +0100342 ToQueuedTask([self = weak_factory_.GetWeakPtr()] {
Harald Alvestrand246724b2019-12-03 22:31:42 +0100343 if (self) {
344 RTC_DCHECK_RUN_ON(self->signaling_thread());
345 self->sctp_data_channels_to_free_.clear();
346 }
Niels Möller236e36c2021-03-23 09:23:10 +0100347 }));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100348 return;
349 }
350 }
351}
352
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100353void DataChannelController::OnTransportChannelClosed() {
354 RTC_DCHECK_RUN_ON(signaling_thread());
Harald Alvestrand7af57c62021-04-16 11:12:14 +0000355 // Use a temporary copy of the SCTP DataChannel list because the
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100356 // DataChannel may callback to us and try to modify the list.
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700357 std::vector<rtc::scoped_refptr<SctpDataChannel>> temp_sctp_dcs;
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100358 temp_sctp_dcs.swap(sctp_data_channels_);
359 for (const auto& channel : temp_sctp_dcs) {
360 channel->OnTransportChannelClosed();
361 }
362}
363
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700364SctpDataChannel* DataChannelController::FindDataChannelBySid(int sid) const {
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100365 RTC_DCHECK_RUN_ON(signaling_thread());
366 for (const auto& channel : sctp_data_channels_) {
367 if (channel->id() == sid) {
368 return channel;
369 }
370 }
371 return nullptr;
372}
373
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +0200374DataChannelTransportInterface* DataChannelController::data_channel_transport()
375 const {
376 // TODO(bugs.webrtc.org/11547): Only allow this accessor to be called on the
377 // network thread.
378 // RTC_DCHECK_RUN_ON(network_thread());
379 return data_channel_transport_;
380}
381
382void DataChannelController::set_data_channel_transport(
383 DataChannelTransportInterface* transport) {
384 RTC_DCHECK_RUN_ON(network_thread());
385 data_channel_transport_ = transport;
386}
387
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +0200388bool DataChannelController::DataChannelSendData(
389 const cricket::SendDataParams& params,
390 const rtc::CopyOnWriteBuffer& payload,
391 cricket::SendDataResult* result) {
392 // TODO(bugs.webrtc.org/11547): Expect method to be called on the network
393 // thread instead. Remove the Invoke() below and move assocated state to
394 // the network thread.
395 RTC_DCHECK_RUN_ON(signaling_thread());
396 RTC_DCHECK(data_channel_transport());
397
398 SendDataParams send_params;
399 send_params.type = ToWebrtcDataMessageType(params.type);
400 send_params.ordered = params.ordered;
401 if (params.max_rtx_count >= 0) {
402 send_params.max_rtx_count = params.max_rtx_count;
403 } else if (params.max_rtx_ms >= 0) {
404 send_params.max_rtx_ms = params.max_rtx_ms;
405 }
406
407 RTCError error = network_thread()->Invoke<RTCError>(
408 RTC_FROM_HERE, [this, params, send_params, payload] {
409 return data_channel_transport()->SendData(params.sid, send_params,
410 payload);
411 });
412
413 if (error.ok()) {
414 *result = cricket::SendDataResult::SDR_SUCCESS;
415 return true;
416 } else if (error.type() == RTCErrorType::RESOURCE_EXHAUSTED) {
417 // SCTP transport uses RESOURCE_EXHAUSTED when it's blocked.
418 // TODO(mellem): Stop using RTCError here and get rid of the mapping.
419 *result = cricket::SendDataResult::SDR_BLOCK;
420 return false;
421 }
422 *result = cricket::SendDataResult::SDR_ERROR;
423 return false;
424}
425
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200426void DataChannelController::NotifyDataChannelsOfTransportCreated() {
427 RTC_DCHECK_RUN_ON(network_thread());
Niels Möller236e36c2021-03-23 09:23:10 +0100428 signaling_thread()->PostTask(
429 ToQueuedTask([self = weak_factory_.GetWeakPtr()] {
430 if (self) {
431 RTC_DCHECK_RUN_ON(self->signaling_thread());
432 for (const auto& channel : self->sctp_data_channels_) {
433 channel->OnTransportChannelCreated();
434 }
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200435 }
Niels Möller236e36c2021-03-23 09:23:10 +0100436 }));
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200437}
438
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100439rtc::Thread* DataChannelController::network_thread() const {
440 return pc_->network_thread();
441}
442rtc::Thread* DataChannelController::signaling_thread() const {
443 return pc_->signaling_thread();
444}
445
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100446} // namespace webrtc