blob: a0df4091ba7df4e5f6763479f2a65cb6dc5dd0a7 [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"
Niels Möller236e36c2021-03-23 09:23:10 +010024#include "rtc_base/task_utils/to_queued_task.h"
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010025
26namespace webrtc {
27
Harald Alvestrand05e4d082019-12-03 14:04:21 +010028bool DataChannelController::HasDataChannels() const {
29 RTC_DCHECK_RUN_ON(signaling_thread());
Harald Alvestrand7af57c62021-04-16 11:12:14 +000030 return !sctp_data_channels_.empty();
Harald Alvestrand05e4d082019-12-03 14:04:21 +010031}
32
Florent Castellid95b1492021-05-10 11:29:56 +020033bool DataChannelController::SendData(int sid,
34 const SendDataParams& params,
Harald Alvestrand05e4d082019-12-03 14:04:21 +010035 const rtc::CopyOnWriteBuffer& payload,
36 cricket::SendDataResult* result) {
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +020037 if (data_channel_transport())
Florent Castellid95b1492021-05-10 11:29:56 +020038 return DataChannelSendData(sid, 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 }
Harald Alvestrand8efc9142022-02-07 10:21:51 +000052 data_transport_writable_callbacks_.AddReceiver(
53 webrtc_data_channel, [webrtc_data_channel](bool ready) {
54 webrtc_data_channel->OnTransportReady(ready);
55 });
56 data_channel_transport_received_data_callbacks_.AddReceiver(
57 webrtc_data_channel,
58 [webrtc_data_channel](const cricket::ReceiveDataParams& params,
59 const rtc::CopyOnWriteBuffer& data) {
60 webrtc_data_channel->OnDataReceived(params, data);
61 });
62 data_channel_transport_channel_closing_callbacks_.AddReceiver(
63 webrtc_data_channel, [webrtc_data_channel](int num) {
64 webrtc_data_channel->OnClosingProcedureStartedRemotely(num);
65 });
66 // When a datachannel is closed, it may get deleted, so we have to make
67 // sure the closed callback isn't called again.
68 // This takes advantage of the fact that a channel is never closed twice.
69 // Unfortunately it doesn't work for pre-opened datachannels, since these
70 // have id = -1 (unassigned) at registration time, so they must be called
71 // upon anyway.
72 int channel_id = webrtc_data_channel->id();
73 data_channel_transport_channel_closed_callbacks_.AddReceiver(
74 webrtc_data_channel, [webrtc_data_channel, channel_id](int num) {
75 if (num == channel_id || channel_id < 0) {
76 webrtc_data_channel->OnClosingProcedureComplete(num);
77 }
78 });
Taylor Brandstetter3a034e12020-07-09 15:32:34 -070079 return true;
80}
81
82void DataChannelController::DisconnectDataChannel(
83 SctpDataChannel* webrtc_data_channel) {
84 RTC_DCHECK_RUN_ON(signaling_thread());
85 if (!data_channel_transport()) {
86 RTC_LOG(LS_ERROR)
87 << "DisconnectDataChannel called when sctp_transport_ is NULL.";
88 return;
Harald Alvestrand00cf34c2019-12-02 09:56:02 +010089 }
Harald Alvestrand8efc9142022-02-07 10:21:51 +000090 data_transport_writable_callbacks_.RemoveReceivers(webrtc_data_channel);
91 data_channel_transport_received_data_callbacks_.RemoveReceivers(
92 webrtc_data_channel);
93 data_channel_transport_channel_closing_callbacks_.RemoveReceivers(
94 webrtc_data_channel);
95 // This function is being called from the OnClosingProcedureComplete
96 // function, which is called from the data_channel_transport_channel_closed
97 // CallbackList.
98 // Since CallbackList does not permit removing receivers in a callback,
99 // schedule the disconnect to happen later.
100 signaling_thread()->PostTask(ToQueuedTask([self = weak_factory_.GetWeakPtr(),
101 webrtc_data_channel]() {
102 if (self) {
103 RTC_DCHECK_RUN_ON(self->signaling_thread());
104 self->data_channel_transport_channel_closed_callbacks_.RemoveReceivers(
105 webrtc_data_channel);
106 }
107 }));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100108}
109
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100110void DataChannelController::AddSctpDataStream(int sid) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100111 if (data_channel_transport()) {
112 network_thread()->Invoke<void>(RTC_FROM_HERE, [this, sid] {
113 if (data_channel_transport()) {
114 data_channel_transport()->OpenChannel(sid);
115 }
116 });
117 }
118}
119
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100120void DataChannelController::RemoveSctpDataStream(int sid) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100121 if (data_channel_transport()) {
122 network_thread()->Invoke<void>(RTC_FROM_HERE, [this, sid] {
123 if (data_channel_transport()) {
124 data_channel_transport()->CloseChannel(sid);
125 }
126 });
127 }
128}
129
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100130bool DataChannelController::ReadyToSendData() const {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100131 RTC_DCHECK_RUN_ON(signaling_thread());
Harald Alvestrand7af57c62021-04-16 11:12:14 +0000132 return (data_channel_transport() && data_channel_transport_ready_to_send_);
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100133}
134
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100135void DataChannelController::OnDataReceived(
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100136 int channel_id,
137 DataMessageType type,
138 const rtc::CopyOnWriteBuffer& buffer) {
139 RTC_DCHECK_RUN_ON(network_thread());
140 cricket::ReceiveDataParams params;
141 params.sid = channel_id;
Florent Castellid95b1492021-05-10 11:29:56 +0200142 params.type = type;
Niels Möller236e36c2021-03-23 09:23:10 +0100143 signaling_thread()->PostTask(
144 ToQueuedTask([self = weak_factory_.GetWeakPtr(), params, buffer] {
145 if (self) {
146 RTC_DCHECK_RUN_ON(self->signaling_thread());
147 // TODO(bugs.webrtc.org/11547): The data being received should be
148 // delivered on the network thread. The way HandleOpenMessage_s works
149 // right now is that it's called for all types of buffers and operates
150 // as a selector function. Change this so that it's only called for
151 // buffers that it should be able to handle. Once we do that, we can
152 // deliver all other buffers on the network thread (change
153 // SignalDataChannelTransportReceivedData_s to
154 // SignalDataChannelTransportReceivedData_n).
155 if (!self->HandleOpenMessage_s(params, buffer)) {
Harald Alvestrand8efc9142022-02-07 10:21:51 +0000156 self->data_channel_transport_received_data_callbacks_.Send(params,
157 buffer);
Niels Möller236e36c2021-03-23 09:23:10 +0100158 }
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100159 }
Niels Möller236e36c2021-03-23 09:23:10 +0100160 }));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100161}
162
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100163void DataChannelController::OnChannelClosing(int channel_id) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100164 RTC_DCHECK_RUN_ON(network_thread());
Niels Möller236e36c2021-03-23 09:23:10 +0100165 signaling_thread()->PostTask(
166 ToQueuedTask([self = weak_factory_.GetWeakPtr(), channel_id] {
167 if (self) {
168 RTC_DCHECK_RUN_ON(self->signaling_thread());
Harald Alvestrand8efc9142022-02-07 10:21:51 +0000169 self->data_channel_transport_channel_closing_callbacks_.Send(
170 channel_id);
Niels Möller236e36c2021-03-23 09:23:10 +0100171 }
172 }));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100173}
174
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100175void DataChannelController::OnChannelClosed(int channel_id) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100176 RTC_DCHECK_RUN_ON(network_thread());
Niels Möller236e36c2021-03-23 09:23:10 +0100177 signaling_thread()->PostTask(
178 ToQueuedTask([self = weak_factory_.GetWeakPtr(), channel_id] {
179 if (self) {
180 RTC_DCHECK_RUN_ON(self->signaling_thread());
Harald Alvestrand8efc9142022-02-07 10:21:51 +0000181 self->data_channel_transport_channel_closed_callbacks_.Send(
182 channel_id);
Niels Möller236e36c2021-03-23 09:23:10 +0100183 }
184 }));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100185}
186
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100187void DataChannelController::OnReadyToSend() {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100188 RTC_DCHECK_RUN_ON(network_thread());
Niels Möller236e36c2021-03-23 09:23:10 +0100189 signaling_thread()->PostTask(
190 ToQueuedTask([self = weak_factory_.GetWeakPtr()] {
191 if (self) {
192 RTC_DCHECK_RUN_ON(self->signaling_thread());
193 self->data_channel_transport_ready_to_send_ = true;
Harald Alvestrand8efc9142022-02-07 10:21:51 +0000194 self->data_transport_writable_callbacks_.Send(
Niels Möller236e36c2021-03-23 09:23:10 +0100195 self->data_channel_transport_ready_to_send_);
196 }
197 }));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100198}
199
Florent Castellidcb9ffc2021-06-29 14:58:23 +0200200void DataChannelController::OnTransportClosed(RTCError error) {
Harald Alvestrand2697ac12019-12-16 10:37:04 +0100201 RTC_DCHECK_RUN_ON(network_thread());
Niels Möller236e36c2021-03-23 09:23:10 +0100202 signaling_thread()->PostTask(
Florent Castellidcb9ffc2021-06-29 14:58:23 +0200203 ToQueuedTask([self = weak_factory_.GetWeakPtr(), error] {
Niels Möller236e36c2021-03-23 09:23:10 +0100204 if (self) {
205 RTC_DCHECK_RUN_ON(self->signaling_thread());
Florent Castellidcb9ffc2021-06-29 14:58:23 +0200206 self->OnTransportChannelClosed(error);
Niels Möller236e36c2021-03-23 09:23:10 +0100207 }
208 }));
Harald Alvestrand2697ac12019-12-16 10:37:04 +0100209}
210
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100211void DataChannelController::SetupDataChannelTransport_n() {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100212 RTC_DCHECK_RUN_ON(network_thread());
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200213
214 // There's a new data channel transport. This needs to be signaled to the
Artem Titov880fa812021-07-30 22:30:23 +0200215 // `sctp_data_channels_` so that they can reopen and reconnect. This is
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200216 // necessary when bundling is applied.
217 NotifyDataChannelsOfTransportCreated();
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100218}
219
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100220void DataChannelController::TeardownDataChannelTransport_n() {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100221 RTC_DCHECK_RUN_ON(network_thread());
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100222 if (data_channel_transport()) {
223 data_channel_transport()->SetDataSink(nullptr);
224 }
225 set_data_channel_transport(nullptr);
226}
227
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100228void DataChannelController::OnTransportChanged(
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100229 DataChannelTransportInterface* new_data_channel_transport) {
230 RTC_DCHECK_RUN_ON(network_thread());
231 if (data_channel_transport() &&
232 data_channel_transport() != new_data_channel_transport) {
Artem Titov880fa812021-07-30 22:30:23 +0200233 // Changed which data channel transport is used for `sctp_mid_` (eg. now
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100234 // it's bundled).
235 data_channel_transport()->SetDataSink(nullptr);
236 set_data_channel_transport(new_data_channel_transport);
237 if (new_data_channel_transport) {
238 new_data_channel_transport->SetDataSink(this);
239
240 // There's a new data channel transport. This needs to be signaled to the
Artem Titov880fa812021-07-30 22:30:23 +0200241 // `sctp_data_channels_` so that they can reopen and reconnect. This is
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100242 // necessary when bundling is applied.
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200243 NotifyDataChannelsOfTransportCreated();
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100244 }
245 }
246}
247
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700248std::vector<DataChannelStats> DataChannelController::GetDataChannelStats()
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200249 const {
250 RTC_DCHECK_RUN_ON(signaling_thread());
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700251 std::vector<DataChannelStats> stats;
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200252 stats.reserve(sctp_data_channels_.size());
253 for (const auto& channel : sctp_data_channels_)
254 stats.push_back(channel->GetStats());
255 return stats;
256}
257
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100258bool DataChannelController::HandleOpenMessage_s(
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100259 const cricket::ReceiveDataParams& params,
260 const rtc::CopyOnWriteBuffer& buffer) {
Florent Castellid95b1492021-05-10 11:29:56 +0200261 if (params.type == DataMessageType::kControl && IsOpenMessage(buffer)) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100262 // Received OPEN message; parse and signal that a new data channel should
263 // be created.
264 std::string label;
265 InternalDataChannelInit config;
Harald Alvestrand7af57c62021-04-16 11:12:14 +0000266 config.id = params.sid;
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100267 if (!ParseDataChannelOpenMessage(buffer, &label, &config)) {
Harald Alvestrand7af57c62021-04-16 11:12:14 +0000268 RTC_LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
269 << params.sid;
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100270 return true;
271 }
272 config.open_handshake_role = InternalDataChannelInit::kAcker;
273 OnDataChannelOpenMessage(label, config);
274 return true;
275 }
276 return false;
277}
278
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100279void DataChannelController::OnDataChannelOpenMessage(
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100280 const std::string& label,
281 const InternalDataChannelInit& config) {
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700282 rtc::scoped_refptr<DataChannelInterface> channel(
283 InternalCreateDataChannelWithProxy(label, &config));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100284 if (!channel.get()) {
285 RTC_LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
286 return;
287 }
288
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700289 pc_->Observer()->OnDataChannel(std::move(channel));
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100290 pc_->NoteDataAddedEvent();
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100291}
292
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700293rtc::scoped_refptr<DataChannelInterface>
294DataChannelController::InternalCreateDataChannelWithProxy(
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100295 const std::string& label,
296 const InternalDataChannelInit* config) {
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100297 RTC_DCHECK_RUN_ON(signaling_thread());
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100298 if (pc_->IsClosed()) {
299 return nullptr;
300 }
Florent Castelli516e2842021-04-19 15:29:50 +0200301
302 rtc::scoped_refptr<SctpDataChannel> channel =
303 InternalCreateSctpDataChannel(label, config);
304 if (channel) {
305 return SctpDataChannel::CreateProxy(channel);
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100306 }
307
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700308 return nullptr;
309}
310
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700311rtc::scoped_refptr<SctpDataChannel>
312DataChannelController::InternalCreateSctpDataChannel(
313 const std::string& label,
314 const InternalDataChannelInit* config) {
315 RTC_DCHECK_RUN_ON(signaling_thread());
316 InternalDataChannelInit new_config =
317 config ? (*config) : InternalDataChannelInit();
318 if (new_config.id < 0) {
319 rtc::SSLRole role;
320 if ((pc_->GetSctpSslRole(&role)) &&
321 !sid_allocator_.AllocateSid(role, &new_config.id)) {
322 RTC_LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
323 return nullptr;
324 }
325 } else if (!sid_allocator_.ReserveSid(new_config.id)) {
326 RTC_LOG(LS_ERROR) << "Failed to create a SCTP data channel "
327 "because the id is already in use or out of range.";
328 return nullptr;
329 }
330 rtc::scoped_refptr<SctpDataChannel> channel(SctpDataChannel::Create(
331 this, label, new_config, signaling_thread(), network_thread()));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100332 if (!channel) {
333 sid_allocator_.ReleaseSid(new_config.id);
334 return nullptr;
335 }
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700336 sctp_data_channels_.push_back(channel);
Harald Alvestrand8efc9142022-02-07 10:21:51 +0000337 channel->SignalClosed.connect(
338 pc_, &PeerConnectionInternal::OnSctpDataChannelClosed);
339 sctp_data_channel_created_callbacks_.Send(channel.get());
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100340 return channel;
341}
342
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100343void DataChannelController::AllocateSctpSids(rtc::SSLRole role) {
344 RTC_DCHECK_RUN_ON(signaling_thread());
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700345 std::vector<rtc::scoped_refptr<SctpDataChannel>> channels_to_close;
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100346 for (const auto& channel : sctp_data_channels_) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100347 if (channel->id() < 0) {
348 int sid;
349 if (!sid_allocator_.AllocateSid(role, &sid)) {
350 RTC_LOG(LS_ERROR) << "Failed to allocate SCTP sid, closing channel.";
351 channels_to_close.push_back(channel);
352 continue;
353 }
354 channel->SetSctpSid(sid);
355 }
356 }
357 // Since closing modifies the list of channels, we have to do the actual
358 // closing outside the loop.
359 for (const auto& channel : channels_to_close) {
Harald Alvestranddfbfb462019-12-08 05:55:43 +0100360 channel->CloseAbruptlyWithDataChannelFailure("Failed to allocate SCTP SID");
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100361 }
362}
363
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700364void DataChannelController::OnSctpDataChannelClosed(SctpDataChannel* channel) {
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100365 RTC_DCHECK_RUN_ON(signaling_thread());
366 for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
367 ++it) {
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100368 if (it->get() == channel) {
369 if (channel->id() >= 0) {
370 // After the closing procedure is done, it's safe to use this ID for
371 // another data channel.
372 sid_allocator_.ReleaseSid(channel->id());
373 }
374 // Since this method is triggered by a signal from the DataChannel,
375 // we can't free it directly here; we need to free it asynchronously.
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100376 sctp_data_channels_to_free_.push_back(*it);
377 sctp_data_channels_.erase(it);
Harald Alvestrand246724b2019-12-03 22:31:42 +0100378 signaling_thread()->PostTask(
Niels Möller236e36c2021-03-23 09:23:10 +0100379 ToQueuedTask([self = weak_factory_.GetWeakPtr()] {
Harald Alvestrand246724b2019-12-03 22:31:42 +0100380 if (self) {
381 RTC_DCHECK_RUN_ON(self->signaling_thread());
382 self->sctp_data_channels_to_free_.clear();
383 }
Niels Möller236e36c2021-03-23 09:23:10 +0100384 }));
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100385 return;
386 }
387 }
388}
389
Florent Castellidcb9ffc2021-06-29 14:58:23 +0200390void DataChannelController::OnTransportChannelClosed(RTCError error) {
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100391 RTC_DCHECK_RUN_ON(signaling_thread());
Harald Alvestrand7af57c62021-04-16 11:12:14 +0000392 // Use a temporary copy of the SCTP DataChannel list because the
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100393 // DataChannel may callback to us and try to modify the list.
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700394 std::vector<rtc::scoped_refptr<SctpDataChannel>> temp_sctp_dcs;
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100395 temp_sctp_dcs.swap(sctp_data_channels_);
396 for (const auto& channel : temp_sctp_dcs) {
Florent Castellidcb9ffc2021-06-29 14:58:23 +0200397 channel->OnTransportChannelClosed(error);
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100398 }
399}
400
Taylor Brandstetter3a034e12020-07-09 15:32:34 -0700401SctpDataChannel* DataChannelController::FindDataChannelBySid(int sid) const {
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100402 RTC_DCHECK_RUN_ON(signaling_thread());
403 for (const auto& channel : sctp_data_channels_) {
404 if (channel->id() == sid) {
405 return channel;
406 }
407 }
408 return nullptr;
409}
410
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +0200411DataChannelTransportInterface* DataChannelController::data_channel_transport()
412 const {
413 // TODO(bugs.webrtc.org/11547): Only allow this accessor to be called on the
414 // network thread.
415 // RTC_DCHECK_RUN_ON(network_thread());
416 return data_channel_transport_;
417}
418
419void DataChannelController::set_data_channel_transport(
420 DataChannelTransportInterface* transport) {
421 RTC_DCHECK_RUN_ON(network_thread());
422 data_channel_transport_ = transport;
423}
424
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +0200425bool DataChannelController::DataChannelSendData(
Florent Castellid95b1492021-05-10 11:29:56 +0200426 int sid,
427 const SendDataParams& params,
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +0200428 const rtc::CopyOnWriteBuffer& payload,
429 cricket::SendDataResult* result) {
430 // TODO(bugs.webrtc.org/11547): Expect method to be called on the network
431 // thread instead. Remove the Invoke() below and move assocated state to
432 // the network thread.
433 RTC_DCHECK_RUN_ON(signaling_thread());
434 RTC_DCHECK(data_channel_transport());
435
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +0200436 RTCError error = network_thread()->Invoke<RTCError>(
Florent Castellid95b1492021-05-10 11:29:56 +0200437 RTC_FROM_HERE, [this, sid, params, payload] {
438 return data_channel_transport()->SendData(sid, params, payload);
Tomas Gunnarsson7d3cfbf2020-06-15 13:47:42 +0200439 });
440
441 if (error.ok()) {
442 *result = cricket::SendDataResult::SDR_SUCCESS;
443 return true;
444 } else if (error.type() == RTCErrorType::RESOURCE_EXHAUSTED) {
445 // SCTP transport uses RESOURCE_EXHAUSTED when it's blocked.
446 // TODO(mellem): Stop using RTCError here and get rid of the mapping.
447 *result = cricket::SendDataResult::SDR_BLOCK;
448 return false;
449 }
450 *result = cricket::SendDataResult::SDR_ERROR;
451 return false;
452}
453
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200454void DataChannelController::NotifyDataChannelsOfTransportCreated() {
455 RTC_DCHECK_RUN_ON(network_thread());
Niels Möller236e36c2021-03-23 09:23:10 +0100456 signaling_thread()->PostTask(
457 ToQueuedTask([self = weak_factory_.GetWeakPtr()] {
458 if (self) {
459 RTC_DCHECK_RUN_ON(self->signaling_thread());
460 for (const auto& channel : self->sctp_data_channels_) {
461 channel->OnTransportChannelCreated();
462 }
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200463 }
Niels Möller236e36c2021-03-23 09:23:10 +0100464 }));
Tomas Gunnarsson2e94de52020-06-16 16:54:10 +0200465}
466
Harald Alvestrand05e4d082019-12-03 14:04:21 +0100467rtc::Thread* DataChannelController::network_thread() const {
468 return pc_->network_thread();
469}
470rtc::Thread* DataChannelController::signaling_thread() const {
471 return pc_->signaling_thread();
472}
473
Harald Alvestrand00cf34c2019-12-02 09:56:02 +0100474} // namespace webrtc