xref: /aosp_15_r20/external/webrtc/pc/data_channel_controller.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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