1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright 2019 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "pc/data_channel_controller.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <utility>
14*d9f75844SAndroid Build Coastguard Worker
15*d9f75844SAndroid Build Coastguard Worker #include "api/peer_connection_interface.h"
16*d9f75844SAndroid Build Coastguard Worker #include "api/rtc_error.h"
17*d9f75844SAndroid Build Coastguard Worker #include "pc/peer_connection_internal.h"
18*d9f75844SAndroid Build Coastguard Worker #include "pc/sctp_utils.h"
19*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
20*d9f75844SAndroid Build Coastguard Worker
21*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
22*d9f75844SAndroid Build Coastguard Worker
~DataChannelController()23*d9f75844SAndroid Build Coastguard Worker DataChannelController::~DataChannelController() {
24*d9f75844SAndroid Build Coastguard Worker // Since channels may have multiple owners, we cannot guarantee that
25*d9f75844SAndroid Build Coastguard Worker // they will be deallocated before destroying the controller.
26*d9f75844SAndroid Build Coastguard Worker // Therefore, detach them from the controller.
27*d9f75844SAndroid Build Coastguard Worker for (auto channel : sctp_data_channels_) {
28*d9f75844SAndroid Build Coastguard Worker channel->DetachFromController();
29*d9f75844SAndroid Build Coastguard Worker }
30*d9f75844SAndroid Build Coastguard Worker }
31*d9f75844SAndroid Build Coastguard Worker
HasDataChannels() const32*d9f75844SAndroid Build Coastguard Worker bool DataChannelController::HasDataChannels() const {
33*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(signaling_thread());
34*d9f75844SAndroid Build Coastguard Worker return !sctp_data_channels_.empty();
35*d9f75844SAndroid Build Coastguard Worker }
36*d9f75844SAndroid Build Coastguard Worker
SendData(int sid,const SendDataParams & params,const rtc::CopyOnWriteBuffer & payload,cricket::SendDataResult * result)37*d9f75844SAndroid Build Coastguard Worker bool DataChannelController::SendData(int sid,
38*d9f75844SAndroid Build Coastguard Worker const SendDataParams& params,
39*d9f75844SAndroid Build Coastguard Worker const rtc::CopyOnWriteBuffer& payload,
40*d9f75844SAndroid Build Coastguard Worker cricket::SendDataResult* result) {
41*d9f75844SAndroid Build Coastguard Worker if (data_channel_transport())
42*d9f75844SAndroid Build Coastguard Worker return DataChannelSendData(sid, params, payload, result);
43*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "SendData called before transport is ready";
44*d9f75844SAndroid Build Coastguard Worker return false;
45*d9f75844SAndroid Build Coastguard Worker }
46*d9f75844SAndroid Build Coastguard Worker
ConnectDataChannel(SctpDataChannel * webrtc_data_channel)47*d9f75844SAndroid Build Coastguard Worker bool DataChannelController::ConnectDataChannel(
48*d9f75844SAndroid Build Coastguard Worker SctpDataChannel* webrtc_data_channel) {
49*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(signaling_thread());
50*d9f75844SAndroid Build Coastguard Worker if (!data_channel_transport()) {
51*d9f75844SAndroid Build Coastguard Worker // Don't log an error here, because DataChannels are expected to call
52*d9f75844SAndroid Build Coastguard Worker // ConnectDataChannel in this state. It's the only way to initially tell
53*d9f75844SAndroid Build Coastguard Worker // whether or not the underlying transport is ready.
54*d9f75844SAndroid Build Coastguard Worker return false;
55*d9f75844SAndroid Build Coastguard Worker }
56*d9f75844SAndroid Build Coastguard Worker SignalDataChannelTransportWritable_s.connect(
57*d9f75844SAndroid Build Coastguard Worker webrtc_data_channel, &SctpDataChannel::OnTransportReady);
58*d9f75844SAndroid Build Coastguard Worker SignalDataChannelTransportReceivedData_s.connect(
59*d9f75844SAndroid Build Coastguard Worker webrtc_data_channel, &SctpDataChannel::OnDataReceived);
60*d9f75844SAndroid Build Coastguard Worker SignalDataChannelTransportChannelClosing_s.connect(
61*d9f75844SAndroid Build Coastguard Worker webrtc_data_channel, &SctpDataChannel::OnClosingProcedureStartedRemotely);
62*d9f75844SAndroid Build Coastguard Worker SignalDataChannelTransportChannelClosed_s.connect(
63*d9f75844SAndroid Build Coastguard Worker webrtc_data_channel, &SctpDataChannel::OnClosingProcedureComplete);
64*d9f75844SAndroid Build Coastguard Worker return true;
65*d9f75844SAndroid Build Coastguard Worker }
66*d9f75844SAndroid Build Coastguard Worker
DisconnectDataChannel(SctpDataChannel * webrtc_data_channel)67*d9f75844SAndroid Build Coastguard Worker void DataChannelController::DisconnectDataChannel(
68*d9f75844SAndroid Build Coastguard Worker SctpDataChannel* webrtc_data_channel) {
69*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(signaling_thread());
70*d9f75844SAndroid Build Coastguard Worker if (!data_channel_transport()) {
71*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR)
72*d9f75844SAndroid Build Coastguard Worker << "DisconnectDataChannel called when sctp_transport_ is NULL.";
73*d9f75844SAndroid Build Coastguard Worker return;
74*d9f75844SAndroid Build Coastguard Worker }
75*d9f75844SAndroid Build Coastguard Worker SignalDataChannelTransportWritable_s.disconnect(webrtc_data_channel);
76*d9f75844SAndroid Build Coastguard Worker SignalDataChannelTransportReceivedData_s.disconnect(webrtc_data_channel);
77*d9f75844SAndroid Build Coastguard Worker SignalDataChannelTransportChannelClosing_s.disconnect(webrtc_data_channel);
78*d9f75844SAndroid Build Coastguard Worker SignalDataChannelTransportChannelClosed_s.disconnect(webrtc_data_channel);
79*d9f75844SAndroid Build Coastguard Worker }
80*d9f75844SAndroid Build Coastguard Worker
AddSctpDataStream(int sid)81*d9f75844SAndroid Build Coastguard Worker void DataChannelController::AddSctpDataStream(int sid) {
82*d9f75844SAndroid Build Coastguard Worker if (data_channel_transport()) {
83*d9f75844SAndroid Build Coastguard Worker network_thread()->BlockingCall([this, sid] {
84*d9f75844SAndroid Build Coastguard Worker if (data_channel_transport()) {
85*d9f75844SAndroid Build Coastguard Worker data_channel_transport()->OpenChannel(sid);
86*d9f75844SAndroid Build Coastguard Worker }
87*d9f75844SAndroid Build Coastguard Worker });
88*d9f75844SAndroid Build Coastguard Worker }
89*d9f75844SAndroid Build Coastguard Worker }
90*d9f75844SAndroid Build Coastguard Worker
RemoveSctpDataStream(int sid)91*d9f75844SAndroid Build Coastguard Worker void DataChannelController::RemoveSctpDataStream(int sid) {
92*d9f75844SAndroid Build Coastguard Worker if (data_channel_transport()) {
93*d9f75844SAndroid Build Coastguard Worker network_thread()->BlockingCall([this, sid] {
94*d9f75844SAndroid Build Coastguard Worker if (data_channel_transport()) {
95*d9f75844SAndroid Build Coastguard Worker data_channel_transport()->CloseChannel(sid);
96*d9f75844SAndroid Build Coastguard Worker }
97*d9f75844SAndroid Build Coastguard Worker });
98*d9f75844SAndroid Build Coastguard Worker }
99*d9f75844SAndroid Build Coastguard Worker }
100*d9f75844SAndroid Build Coastguard Worker
ReadyToSendData() const101*d9f75844SAndroid Build Coastguard Worker bool DataChannelController::ReadyToSendData() const {
102*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(signaling_thread());
103*d9f75844SAndroid Build Coastguard Worker return (data_channel_transport() && data_channel_transport_ready_to_send_);
104*d9f75844SAndroid Build Coastguard Worker }
105*d9f75844SAndroid Build Coastguard Worker
OnDataReceived(int channel_id,DataMessageType type,const rtc::CopyOnWriteBuffer & buffer)106*d9f75844SAndroid Build Coastguard Worker void DataChannelController::OnDataReceived(
107*d9f75844SAndroid Build Coastguard Worker int channel_id,
108*d9f75844SAndroid Build Coastguard Worker DataMessageType type,
109*d9f75844SAndroid Build Coastguard Worker const rtc::CopyOnWriteBuffer& buffer) {
110*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread());
111*d9f75844SAndroid Build Coastguard Worker cricket::ReceiveDataParams params;
112*d9f75844SAndroid Build Coastguard Worker params.sid = channel_id;
113*d9f75844SAndroid Build Coastguard Worker params.type = type;
114*d9f75844SAndroid Build Coastguard Worker signaling_thread()->PostTask(
115*d9f75844SAndroid Build Coastguard Worker [self = weak_factory_.GetWeakPtr(), params, buffer] {
116*d9f75844SAndroid Build Coastguard Worker if (self) {
117*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(self->signaling_thread());
118*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/11547): The data being received should be
119*d9f75844SAndroid Build Coastguard Worker // delivered on the network thread. The way HandleOpenMessage_s works
120*d9f75844SAndroid Build Coastguard Worker // right now is that it's called for all types of buffers and operates
121*d9f75844SAndroid Build Coastguard Worker // as a selector function. Change this so that it's only called for
122*d9f75844SAndroid Build Coastguard Worker // buffers that it should be able to handle. Once we do that, we can
123*d9f75844SAndroid Build Coastguard Worker // deliver all other buffers on the network thread (change
124*d9f75844SAndroid Build Coastguard Worker // SignalDataChannelTransportReceivedData_s to
125*d9f75844SAndroid Build Coastguard Worker // SignalDataChannelTransportReceivedData_n).
126*d9f75844SAndroid Build Coastguard Worker if (!self->HandleOpenMessage_s(params, buffer)) {
127*d9f75844SAndroid Build Coastguard Worker self->SignalDataChannelTransportReceivedData_s(params, buffer);
128*d9f75844SAndroid Build Coastguard Worker }
129*d9f75844SAndroid Build Coastguard Worker }
130*d9f75844SAndroid Build Coastguard Worker });
131*d9f75844SAndroid Build Coastguard Worker }
132*d9f75844SAndroid Build Coastguard Worker
OnChannelClosing(int channel_id)133*d9f75844SAndroid Build Coastguard Worker void DataChannelController::OnChannelClosing(int channel_id) {
134*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread());
135*d9f75844SAndroid Build Coastguard Worker signaling_thread()->PostTask([self = weak_factory_.GetWeakPtr(), channel_id] {
136*d9f75844SAndroid Build Coastguard Worker if (self) {
137*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(self->signaling_thread());
138*d9f75844SAndroid Build Coastguard Worker self->SignalDataChannelTransportChannelClosing_s(channel_id);
139*d9f75844SAndroid Build Coastguard Worker }
140*d9f75844SAndroid Build Coastguard Worker });
141*d9f75844SAndroid Build Coastguard Worker }
142*d9f75844SAndroid Build Coastguard Worker
OnChannelClosed(int channel_id)143*d9f75844SAndroid Build Coastguard Worker void DataChannelController::OnChannelClosed(int channel_id) {
144*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread());
145*d9f75844SAndroid Build Coastguard Worker signaling_thread()->PostTask([self = weak_factory_.GetWeakPtr(), channel_id] {
146*d9f75844SAndroid Build Coastguard Worker if (self) {
147*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(self->signaling_thread());
148*d9f75844SAndroid Build Coastguard Worker self->SignalDataChannelTransportChannelClosed_s(channel_id);
149*d9f75844SAndroid Build Coastguard Worker }
150*d9f75844SAndroid Build Coastguard Worker });
151*d9f75844SAndroid Build Coastguard Worker }
152*d9f75844SAndroid Build Coastguard Worker
OnReadyToSend()153*d9f75844SAndroid Build Coastguard Worker void DataChannelController::OnReadyToSend() {
154*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread());
155*d9f75844SAndroid Build Coastguard Worker signaling_thread()->PostTask([self = weak_factory_.GetWeakPtr()] {
156*d9f75844SAndroid Build Coastguard Worker if (self) {
157*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(self->signaling_thread());
158*d9f75844SAndroid Build Coastguard Worker self->data_channel_transport_ready_to_send_ = true;
159*d9f75844SAndroid Build Coastguard Worker self->SignalDataChannelTransportWritable_s(
160*d9f75844SAndroid Build Coastguard Worker self->data_channel_transport_ready_to_send_);
161*d9f75844SAndroid Build Coastguard Worker }
162*d9f75844SAndroid Build Coastguard Worker });
163*d9f75844SAndroid Build Coastguard Worker }
164*d9f75844SAndroid Build Coastguard Worker
OnTransportClosed(RTCError error)165*d9f75844SAndroid Build Coastguard Worker void DataChannelController::OnTransportClosed(RTCError error) {
166*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread());
167*d9f75844SAndroid Build Coastguard Worker signaling_thread()->PostTask([self = weak_factory_.GetWeakPtr(), error] {
168*d9f75844SAndroid Build Coastguard Worker if (self) {
169*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(self->signaling_thread());
170*d9f75844SAndroid Build Coastguard Worker self->OnTransportChannelClosed(error);
171*d9f75844SAndroid Build Coastguard Worker }
172*d9f75844SAndroid Build Coastguard Worker });
173*d9f75844SAndroid Build Coastguard Worker }
174*d9f75844SAndroid Build Coastguard Worker
SetupDataChannelTransport_n()175*d9f75844SAndroid Build Coastguard Worker void DataChannelController::SetupDataChannelTransport_n() {
176*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread());
177*d9f75844SAndroid Build Coastguard Worker
178*d9f75844SAndroid Build Coastguard Worker // There's a new data channel transport. This needs to be signaled to the
179*d9f75844SAndroid Build Coastguard Worker // `sctp_data_channels_` so that they can reopen and reconnect. This is
180*d9f75844SAndroid Build Coastguard Worker // necessary when bundling is applied.
181*d9f75844SAndroid Build Coastguard Worker NotifyDataChannelsOfTransportCreated();
182*d9f75844SAndroid Build Coastguard Worker }
183*d9f75844SAndroid Build Coastguard Worker
TeardownDataChannelTransport_n()184*d9f75844SAndroid Build Coastguard Worker void DataChannelController::TeardownDataChannelTransport_n() {
185*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread());
186*d9f75844SAndroid Build Coastguard Worker if (data_channel_transport()) {
187*d9f75844SAndroid Build Coastguard Worker data_channel_transport()->SetDataSink(nullptr);
188*d9f75844SAndroid Build Coastguard Worker }
189*d9f75844SAndroid Build Coastguard Worker set_data_channel_transport(nullptr);
190*d9f75844SAndroid Build Coastguard Worker }
191*d9f75844SAndroid Build Coastguard Worker
OnTransportChanged(DataChannelTransportInterface * new_data_channel_transport)192*d9f75844SAndroid Build Coastguard Worker void DataChannelController::OnTransportChanged(
193*d9f75844SAndroid Build Coastguard Worker DataChannelTransportInterface* new_data_channel_transport) {
194*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread());
195*d9f75844SAndroid Build Coastguard Worker if (data_channel_transport() &&
196*d9f75844SAndroid Build Coastguard Worker data_channel_transport() != new_data_channel_transport) {
197*d9f75844SAndroid Build Coastguard Worker // Changed which data channel transport is used for `sctp_mid_` (eg. now
198*d9f75844SAndroid Build Coastguard Worker // it's bundled).
199*d9f75844SAndroid Build Coastguard Worker data_channel_transport()->SetDataSink(nullptr);
200*d9f75844SAndroid Build Coastguard Worker set_data_channel_transport(new_data_channel_transport);
201*d9f75844SAndroid Build Coastguard Worker if (new_data_channel_transport) {
202*d9f75844SAndroid Build Coastguard Worker new_data_channel_transport->SetDataSink(this);
203*d9f75844SAndroid Build Coastguard Worker
204*d9f75844SAndroid Build Coastguard Worker // There's a new data channel transport. This needs to be signaled to the
205*d9f75844SAndroid Build Coastguard Worker // `sctp_data_channels_` so that they can reopen and reconnect. This is
206*d9f75844SAndroid Build Coastguard Worker // necessary when bundling is applied.
207*d9f75844SAndroid Build Coastguard Worker NotifyDataChannelsOfTransportCreated();
208*d9f75844SAndroid Build Coastguard Worker }
209*d9f75844SAndroid Build Coastguard Worker }
210*d9f75844SAndroid Build Coastguard Worker }
211*d9f75844SAndroid Build Coastguard Worker
GetDataChannelStats() const212*d9f75844SAndroid Build Coastguard Worker std::vector<DataChannelStats> DataChannelController::GetDataChannelStats()
213*d9f75844SAndroid Build Coastguard Worker const {
214*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(signaling_thread());
215*d9f75844SAndroid Build Coastguard Worker std::vector<DataChannelStats> stats;
216*d9f75844SAndroid Build Coastguard Worker stats.reserve(sctp_data_channels_.size());
217*d9f75844SAndroid Build Coastguard Worker for (const auto& channel : sctp_data_channels_)
218*d9f75844SAndroid Build Coastguard Worker stats.push_back(channel->GetStats());
219*d9f75844SAndroid Build Coastguard Worker return stats;
220*d9f75844SAndroid Build Coastguard Worker }
221*d9f75844SAndroid Build Coastguard Worker
HandleOpenMessage_s(const cricket::ReceiveDataParams & params,const rtc::CopyOnWriteBuffer & buffer)222*d9f75844SAndroid Build Coastguard Worker bool DataChannelController::HandleOpenMessage_s(
223*d9f75844SAndroid Build Coastguard Worker const cricket::ReceiveDataParams& params,
224*d9f75844SAndroid Build Coastguard Worker const rtc::CopyOnWriteBuffer& buffer) {
225*d9f75844SAndroid Build Coastguard Worker if (params.type == DataMessageType::kControl && IsOpenMessage(buffer)) {
226*d9f75844SAndroid Build Coastguard Worker // Received OPEN message; parse and signal that a new data channel should
227*d9f75844SAndroid Build Coastguard Worker // be created.
228*d9f75844SAndroid Build Coastguard Worker std::string label;
229*d9f75844SAndroid Build Coastguard Worker InternalDataChannelInit config;
230*d9f75844SAndroid Build Coastguard Worker config.id = params.sid;
231*d9f75844SAndroid Build Coastguard Worker if (!ParseDataChannelOpenMessage(buffer, &label, &config)) {
232*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
233*d9f75844SAndroid Build Coastguard Worker << params.sid;
234*d9f75844SAndroid Build Coastguard Worker return true;
235*d9f75844SAndroid Build Coastguard Worker }
236*d9f75844SAndroid Build Coastguard Worker config.open_handshake_role = InternalDataChannelInit::kAcker;
237*d9f75844SAndroid Build Coastguard Worker OnDataChannelOpenMessage(label, config);
238*d9f75844SAndroid Build Coastguard Worker return true;
239*d9f75844SAndroid Build Coastguard Worker }
240*d9f75844SAndroid Build Coastguard Worker return false;
241*d9f75844SAndroid Build Coastguard Worker }
242*d9f75844SAndroid Build Coastguard Worker
OnDataChannelOpenMessage(const std::string & label,const InternalDataChannelInit & config)243*d9f75844SAndroid Build Coastguard Worker void DataChannelController::OnDataChannelOpenMessage(
244*d9f75844SAndroid Build Coastguard Worker const std::string& label,
245*d9f75844SAndroid Build Coastguard Worker const InternalDataChannelInit& config) {
246*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<DataChannelInterface> channel(
247*d9f75844SAndroid Build Coastguard Worker InternalCreateDataChannelWithProxy(label, &config));
248*d9f75844SAndroid Build Coastguard Worker if (!channel.get()) {
249*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
250*d9f75844SAndroid Build Coastguard Worker return;
251*d9f75844SAndroid Build Coastguard Worker }
252*d9f75844SAndroid Build Coastguard Worker
253*d9f75844SAndroid Build Coastguard Worker pc_->Observer()->OnDataChannel(std::move(channel));
254*d9f75844SAndroid Build Coastguard Worker pc_->NoteDataAddedEvent();
255*d9f75844SAndroid Build Coastguard Worker }
256*d9f75844SAndroid Build Coastguard Worker
257*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<DataChannelInterface>
InternalCreateDataChannelWithProxy(const std::string & label,const InternalDataChannelInit * config)258*d9f75844SAndroid Build Coastguard Worker DataChannelController::InternalCreateDataChannelWithProxy(
259*d9f75844SAndroid Build Coastguard Worker const std::string& label,
260*d9f75844SAndroid Build Coastguard Worker const InternalDataChannelInit* config) {
261*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(signaling_thread());
262*d9f75844SAndroid Build Coastguard Worker if (pc_->IsClosed()) {
263*d9f75844SAndroid Build Coastguard Worker return nullptr;
264*d9f75844SAndroid Build Coastguard Worker }
265*d9f75844SAndroid Build Coastguard Worker
266*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<SctpDataChannel> channel =
267*d9f75844SAndroid Build Coastguard Worker InternalCreateSctpDataChannel(label, config);
268*d9f75844SAndroid Build Coastguard Worker if (channel) {
269*d9f75844SAndroid Build Coastguard Worker return SctpDataChannel::CreateProxy(channel);
270*d9f75844SAndroid Build Coastguard Worker }
271*d9f75844SAndroid Build Coastguard Worker
272*d9f75844SAndroid Build Coastguard Worker return nullptr;
273*d9f75844SAndroid Build Coastguard Worker }
274*d9f75844SAndroid Build Coastguard Worker
275*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<SctpDataChannel>
InternalCreateSctpDataChannel(const std::string & label,const InternalDataChannelInit * config)276*d9f75844SAndroid Build Coastguard Worker DataChannelController::InternalCreateSctpDataChannel(
277*d9f75844SAndroid Build Coastguard Worker const std::string& label,
278*d9f75844SAndroid Build Coastguard Worker const InternalDataChannelInit* config) {
279*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(signaling_thread());
280*d9f75844SAndroid Build Coastguard Worker InternalDataChannelInit new_config =
281*d9f75844SAndroid Build Coastguard Worker config ? (*config) : InternalDataChannelInit();
282*d9f75844SAndroid Build Coastguard Worker if (new_config.id < 0) {
283*d9f75844SAndroid Build Coastguard Worker rtc::SSLRole role;
284*d9f75844SAndroid Build Coastguard Worker if ((pc_->GetSctpSslRole(&role)) &&
285*d9f75844SAndroid Build Coastguard Worker !sid_allocator_.AllocateSid(role, &new_config.id)) {
286*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "No id can be allocated for the SCTP data channel.";
287*d9f75844SAndroid Build Coastguard Worker return nullptr;
288*d9f75844SAndroid Build Coastguard Worker }
289*d9f75844SAndroid Build Coastguard Worker } else if (!sid_allocator_.ReserveSid(new_config.id)) {
290*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Failed to create a SCTP data channel "
291*d9f75844SAndroid Build Coastguard Worker "because the id is already in use or out of range.";
292*d9f75844SAndroid Build Coastguard Worker return nullptr;
293*d9f75844SAndroid Build Coastguard Worker }
294*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<SctpDataChannel> channel(SctpDataChannel::Create(
295*d9f75844SAndroid Build Coastguard Worker this, label, new_config, signaling_thread(), network_thread()));
296*d9f75844SAndroid Build Coastguard Worker if (!channel) {
297*d9f75844SAndroid Build Coastguard Worker sid_allocator_.ReleaseSid(new_config.id);
298*d9f75844SAndroid Build Coastguard Worker return nullptr;
299*d9f75844SAndroid Build Coastguard Worker }
300*d9f75844SAndroid Build Coastguard Worker sctp_data_channels_.push_back(channel);
301*d9f75844SAndroid Build Coastguard Worker channel->SignalClosed.connect(
302*d9f75844SAndroid Build Coastguard Worker pc_, &PeerConnectionInternal::OnSctpDataChannelClosed);
303*d9f75844SAndroid Build Coastguard Worker SignalSctpDataChannelCreated_(channel.get());
304*d9f75844SAndroid Build Coastguard Worker return channel;
305*d9f75844SAndroid Build Coastguard Worker }
306*d9f75844SAndroid Build Coastguard Worker
AllocateSctpSids(rtc::SSLRole role)307*d9f75844SAndroid Build Coastguard Worker void DataChannelController::AllocateSctpSids(rtc::SSLRole role) {
308*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(signaling_thread());
309*d9f75844SAndroid Build Coastguard Worker std::vector<rtc::scoped_refptr<SctpDataChannel>> channels_to_close;
310*d9f75844SAndroid Build Coastguard Worker for (const auto& channel : sctp_data_channels_) {
311*d9f75844SAndroid Build Coastguard Worker if (channel->id() < 0) {
312*d9f75844SAndroid Build Coastguard Worker int sid;
313*d9f75844SAndroid Build Coastguard Worker if (!sid_allocator_.AllocateSid(role, &sid)) {
314*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR) << "Failed to allocate SCTP sid, closing channel.";
315*d9f75844SAndroid Build Coastguard Worker channels_to_close.push_back(channel);
316*d9f75844SAndroid Build Coastguard Worker continue;
317*d9f75844SAndroid Build Coastguard Worker }
318*d9f75844SAndroid Build Coastguard Worker channel->SetSctpSid(sid);
319*d9f75844SAndroid Build Coastguard Worker }
320*d9f75844SAndroid Build Coastguard Worker }
321*d9f75844SAndroid Build Coastguard Worker // Since closing modifies the list of channels, we have to do the actual
322*d9f75844SAndroid Build Coastguard Worker // closing outside the loop.
323*d9f75844SAndroid Build Coastguard Worker for (const auto& channel : channels_to_close) {
324*d9f75844SAndroid Build Coastguard Worker channel->CloseAbruptlyWithDataChannelFailure("Failed to allocate SCTP SID");
325*d9f75844SAndroid Build Coastguard Worker }
326*d9f75844SAndroid Build Coastguard Worker }
327*d9f75844SAndroid Build Coastguard Worker
OnSctpDataChannelClosed(SctpDataChannel * channel)328*d9f75844SAndroid Build Coastguard Worker void DataChannelController::OnSctpDataChannelClosed(SctpDataChannel* channel) {
329*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(signaling_thread());
330*d9f75844SAndroid Build Coastguard Worker for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
331*d9f75844SAndroid Build Coastguard Worker ++it) {
332*d9f75844SAndroid Build Coastguard Worker if (it->get() == channel) {
333*d9f75844SAndroid Build Coastguard Worker if (channel->id() >= 0) {
334*d9f75844SAndroid Build Coastguard Worker // After the closing procedure is done, it's safe to use this ID for
335*d9f75844SAndroid Build Coastguard Worker // another data channel.
336*d9f75844SAndroid Build Coastguard Worker sid_allocator_.ReleaseSid(channel->id());
337*d9f75844SAndroid Build Coastguard Worker }
338*d9f75844SAndroid Build Coastguard Worker // Since this method is triggered by a signal from the DataChannel,
339*d9f75844SAndroid Build Coastguard Worker // we can't free it directly here; we need to free it asynchronously.
340*d9f75844SAndroid Build Coastguard Worker sctp_data_channels_to_free_.push_back(*it);
341*d9f75844SAndroid Build Coastguard Worker sctp_data_channels_.erase(it);
342*d9f75844SAndroid Build Coastguard Worker signaling_thread()->PostTask([self = weak_factory_.GetWeakPtr()] {
343*d9f75844SAndroid Build Coastguard Worker if (self) {
344*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(self->signaling_thread());
345*d9f75844SAndroid Build Coastguard Worker self->sctp_data_channels_to_free_.clear();
346*d9f75844SAndroid Build Coastguard Worker }
347*d9f75844SAndroid Build Coastguard Worker });
348*d9f75844SAndroid Build Coastguard Worker return;
349*d9f75844SAndroid Build Coastguard Worker }
350*d9f75844SAndroid Build Coastguard Worker }
351*d9f75844SAndroid Build Coastguard Worker }
352*d9f75844SAndroid Build Coastguard Worker
OnTransportChannelClosed(RTCError error)353*d9f75844SAndroid Build Coastguard Worker void DataChannelController::OnTransportChannelClosed(RTCError error) {
354*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(signaling_thread());
355*d9f75844SAndroid Build Coastguard Worker // Use a temporary copy of the SCTP DataChannel list because the
356*d9f75844SAndroid Build Coastguard Worker // DataChannel may callback to us and try to modify the list.
357*d9f75844SAndroid Build Coastguard Worker std::vector<rtc::scoped_refptr<SctpDataChannel>> temp_sctp_dcs;
358*d9f75844SAndroid Build Coastguard Worker temp_sctp_dcs.swap(sctp_data_channels_);
359*d9f75844SAndroid Build Coastguard Worker for (const auto& channel : temp_sctp_dcs) {
360*d9f75844SAndroid Build Coastguard Worker channel->OnTransportChannelClosed(error);
361*d9f75844SAndroid Build Coastguard Worker }
362*d9f75844SAndroid Build Coastguard Worker }
363*d9f75844SAndroid Build Coastguard Worker
data_channel_transport() const364*d9f75844SAndroid Build Coastguard Worker DataChannelTransportInterface* DataChannelController::data_channel_transport()
365*d9f75844SAndroid Build Coastguard Worker const {
366*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/11547): Only allow this accessor to be called on the
367*d9f75844SAndroid Build Coastguard Worker // network thread.
368*d9f75844SAndroid Build Coastguard Worker // RTC_DCHECK_RUN_ON(network_thread());
369*d9f75844SAndroid Build Coastguard Worker return data_channel_transport_;
370*d9f75844SAndroid Build Coastguard Worker }
371*d9f75844SAndroid Build Coastguard Worker
set_data_channel_transport(DataChannelTransportInterface * transport)372*d9f75844SAndroid Build Coastguard Worker void DataChannelController::set_data_channel_transport(
373*d9f75844SAndroid Build Coastguard Worker DataChannelTransportInterface* transport) {
374*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread());
375*d9f75844SAndroid Build Coastguard Worker data_channel_transport_ = transport;
376*d9f75844SAndroid Build Coastguard Worker }
377*d9f75844SAndroid Build Coastguard Worker
DataChannelSendData(int sid,const SendDataParams & params,const rtc::CopyOnWriteBuffer & payload,cricket::SendDataResult * result)378*d9f75844SAndroid Build Coastguard Worker bool DataChannelController::DataChannelSendData(
379*d9f75844SAndroid Build Coastguard Worker int sid,
380*d9f75844SAndroid Build Coastguard Worker const SendDataParams& params,
381*d9f75844SAndroid Build Coastguard Worker const rtc::CopyOnWriteBuffer& payload,
382*d9f75844SAndroid Build Coastguard Worker cricket::SendDataResult* result) {
383*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/11547): Expect method to be called on the network
384*d9f75844SAndroid Build Coastguard Worker // thread instead. Remove the BlockingCall() below and move assocated state to
385*d9f75844SAndroid Build Coastguard Worker // the network thread.
386*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(signaling_thread());
387*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(data_channel_transport());
388*d9f75844SAndroid Build Coastguard Worker
389*d9f75844SAndroid Build Coastguard Worker RTCError error = network_thread()->BlockingCall([this, sid, params, payload] {
390*d9f75844SAndroid Build Coastguard Worker return data_channel_transport()->SendData(sid, params, payload);
391*d9f75844SAndroid Build Coastguard Worker });
392*d9f75844SAndroid Build Coastguard Worker
393*d9f75844SAndroid Build Coastguard Worker if (error.ok()) {
394*d9f75844SAndroid Build Coastguard Worker *result = cricket::SendDataResult::SDR_SUCCESS;
395*d9f75844SAndroid Build Coastguard Worker return true;
396*d9f75844SAndroid Build Coastguard Worker } else if (error.type() == RTCErrorType::RESOURCE_EXHAUSTED) {
397*d9f75844SAndroid Build Coastguard Worker // SCTP transport uses RESOURCE_EXHAUSTED when it's blocked.
398*d9f75844SAndroid Build Coastguard Worker // TODO(mellem): Stop using RTCError here and get rid of the mapping.
399*d9f75844SAndroid Build Coastguard Worker *result = cricket::SendDataResult::SDR_BLOCK;
400*d9f75844SAndroid Build Coastguard Worker return false;
401*d9f75844SAndroid Build Coastguard Worker }
402*d9f75844SAndroid Build Coastguard Worker *result = cricket::SendDataResult::SDR_ERROR;
403*d9f75844SAndroid Build Coastguard Worker return false;
404*d9f75844SAndroid Build Coastguard Worker }
405*d9f75844SAndroid Build Coastguard Worker
NotifyDataChannelsOfTransportCreated()406*d9f75844SAndroid Build Coastguard Worker void DataChannelController::NotifyDataChannelsOfTransportCreated() {
407*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(network_thread());
408*d9f75844SAndroid Build Coastguard Worker signaling_thread()->PostTask([self = weak_factory_.GetWeakPtr()] {
409*d9f75844SAndroid Build Coastguard Worker if (self) {
410*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(self->signaling_thread());
411*d9f75844SAndroid Build Coastguard Worker for (const auto& channel : self->sctp_data_channels_) {
412*d9f75844SAndroid Build Coastguard Worker channel->OnTransportChannelCreated();
413*d9f75844SAndroid Build Coastguard Worker }
414*d9f75844SAndroid Build Coastguard Worker }
415*d9f75844SAndroid Build Coastguard Worker });
416*d9f75844SAndroid Build Coastguard Worker }
417*d9f75844SAndroid Build Coastguard Worker
network_thread() const418*d9f75844SAndroid Build Coastguard Worker rtc::Thread* DataChannelController::network_thread() const {
419*d9f75844SAndroid Build Coastguard Worker return pc_->network_thread();
420*d9f75844SAndroid Build Coastguard Worker }
signaling_thread() const421*d9f75844SAndroid Build Coastguard Worker rtc::Thread* DataChannelController::signaling_thread() const {
422*d9f75844SAndroid Build Coastguard Worker return pc_->signaling_thread();
423*d9f75844SAndroid Build Coastguard Worker }
424*d9f75844SAndroid Build Coastguard Worker
425*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
426