xref: /aosp_15_r20/external/webrtc/pc/sctp_data_channel.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright 2020 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/sctp_data_channel.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <limits>
14*d9f75844SAndroid Build Coastguard Worker #include <memory>
15*d9f75844SAndroid Build Coastguard Worker #include <string>
16*d9f75844SAndroid Build Coastguard Worker #include <utility>
17*d9f75844SAndroid Build Coastguard Worker 
18*d9f75844SAndroid Build Coastguard Worker #include "absl/cleanup/cleanup.h"
19*d9f75844SAndroid Build Coastguard Worker #include "media/sctp/sctp_transport_internal.h"
20*d9f75844SAndroid Build Coastguard Worker #include "pc/proxy.h"
21*d9f75844SAndroid Build Coastguard Worker #include "pc/sctp_utils.h"
22*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
23*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
24*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/system/unused.h"
25*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/thread.h"
26*d9f75844SAndroid Build Coastguard Worker 
27*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
28*d9f75844SAndroid Build Coastguard Worker 
29*d9f75844SAndroid Build Coastguard Worker namespace {
30*d9f75844SAndroid Build Coastguard Worker 
31*d9f75844SAndroid Build Coastguard Worker static size_t kMaxQueuedReceivedDataBytes = 16 * 1024 * 1024;
32*d9f75844SAndroid Build Coastguard Worker 
33*d9f75844SAndroid Build Coastguard Worker static std::atomic<int> g_unique_id{0};
34*d9f75844SAndroid Build Coastguard Worker 
GenerateUniqueId()35*d9f75844SAndroid Build Coastguard Worker int GenerateUniqueId() {
36*d9f75844SAndroid Build Coastguard Worker   return ++g_unique_id;
37*d9f75844SAndroid Build Coastguard Worker }
38*d9f75844SAndroid Build Coastguard Worker 
39*d9f75844SAndroid Build Coastguard Worker // Define proxy for DataChannelInterface.
40*d9f75844SAndroid Build Coastguard Worker BEGIN_PRIMARY_PROXY_MAP(DataChannel)
41*d9f75844SAndroid Build Coastguard Worker PROXY_PRIMARY_THREAD_DESTRUCTOR()
42*d9f75844SAndroid Build Coastguard Worker PROXY_METHOD1(void, RegisterObserver, DataChannelObserver*)
43*d9f75844SAndroid Build Coastguard Worker PROXY_METHOD0(void, UnregisterObserver)
44*d9f75844SAndroid Build Coastguard Worker BYPASS_PROXY_CONSTMETHOD0(std::string, label)
45*d9f75844SAndroid Build Coastguard Worker BYPASS_PROXY_CONSTMETHOD0(bool, reliable)
46*d9f75844SAndroid Build Coastguard Worker BYPASS_PROXY_CONSTMETHOD0(bool, ordered)
47*d9f75844SAndroid Build Coastguard Worker BYPASS_PROXY_CONSTMETHOD0(uint16_t, maxRetransmitTime)
48*d9f75844SAndroid Build Coastguard Worker BYPASS_PROXY_CONSTMETHOD0(uint16_t, maxRetransmits)
49*d9f75844SAndroid Build Coastguard Worker BYPASS_PROXY_CONSTMETHOD0(absl::optional<int>, maxRetransmitsOpt)
50*d9f75844SAndroid Build Coastguard Worker BYPASS_PROXY_CONSTMETHOD0(absl::optional<int>, maxPacketLifeTime)
51*d9f75844SAndroid Build Coastguard Worker BYPASS_PROXY_CONSTMETHOD0(std::string, protocol)
52*d9f75844SAndroid Build Coastguard Worker BYPASS_PROXY_CONSTMETHOD0(bool, negotiated)
53*d9f75844SAndroid Build Coastguard Worker // Can't bypass the proxy since the id may change.
54*d9f75844SAndroid Build Coastguard Worker PROXY_CONSTMETHOD0(int, id)
55*d9f75844SAndroid Build Coastguard Worker BYPASS_PROXY_CONSTMETHOD0(Priority, priority)
56*d9f75844SAndroid Build Coastguard Worker PROXY_CONSTMETHOD0(DataState, state)
57*d9f75844SAndroid Build Coastguard Worker PROXY_CONSTMETHOD0(RTCError, error)
58*d9f75844SAndroid Build Coastguard Worker PROXY_CONSTMETHOD0(uint32_t, messages_sent)
59*d9f75844SAndroid Build Coastguard Worker PROXY_CONSTMETHOD0(uint64_t, bytes_sent)
60*d9f75844SAndroid Build Coastguard Worker PROXY_CONSTMETHOD0(uint32_t, messages_received)
61*d9f75844SAndroid Build Coastguard Worker PROXY_CONSTMETHOD0(uint64_t, bytes_received)
62*d9f75844SAndroid Build Coastguard Worker PROXY_CONSTMETHOD0(uint64_t, buffered_amount)
63*d9f75844SAndroid Build Coastguard Worker PROXY_METHOD0(void, Close)
64*d9f75844SAndroid Build Coastguard Worker // TODO(bugs.webrtc.org/11547): Change to run on the network thread.
65*d9f75844SAndroid Build Coastguard Worker PROXY_METHOD1(bool, Send, const DataBuffer&)
66*d9f75844SAndroid Build Coastguard Worker END_PROXY_MAP(DataChannel)
67*d9f75844SAndroid Build Coastguard Worker 
68*d9f75844SAndroid Build Coastguard Worker }  // namespace
69*d9f75844SAndroid Build Coastguard Worker 
InternalDataChannelInit(const DataChannelInit & base)70*d9f75844SAndroid Build Coastguard Worker InternalDataChannelInit::InternalDataChannelInit(const DataChannelInit& base)
71*d9f75844SAndroid Build Coastguard Worker     : DataChannelInit(base), open_handshake_role(kOpener) {
72*d9f75844SAndroid Build Coastguard Worker   // If the channel is externally negotiated, do not send the OPEN message.
73*d9f75844SAndroid Build Coastguard Worker   if (base.negotiated) {
74*d9f75844SAndroid Build Coastguard Worker     open_handshake_role = kNone;
75*d9f75844SAndroid Build Coastguard Worker   } else {
76*d9f75844SAndroid Build Coastguard Worker     // Datachannel is externally negotiated. Ignore the id value.
77*d9f75844SAndroid Build Coastguard Worker     // Specified in createDataChannel, WebRTC spec section 6.1 bullet 13.
78*d9f75844SAndroid Build Coastguard Worker     id = -1;
79*d9f75844SAndroid Build Coastguard Worker   }
80*d9f75844SAndroid Build Coastguard Worker   // Backwards compatibility: If maxRetransmits or maxRetransmitTime
81*d9f75844SAndroid Build Coastguard Worker   // are negative, the feature is not enabled.
82*d9f75844SAndroid Build Coastguard Worker   // Values are clamped to a 16bit range.
83*d9f75844SAndroid Build Coastguard Worker   if (maxRetransmits) {
84*d9f75844SAndroid Build Coastguard Worker     if (*maxRetransmits < 0) {
85*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_ERROR)
86*d9f75844SAndroid Build Coastguard Worker           << "Accepting maxRetransmits < 0 for backwards compatibility";
87*d9f75844SAndroid Build Coastguard Worker       maxRetransmits = absl::nullopt;
88*d9f75844SAndroid Build Coastguard Worker     } else if (*maxRetransmits > std::numeric_limits<uint16_t>::max()) {
89*d9f75844SAndroid Build Coastguard Worker       maxRetransmits = std::numeric_limits<uint16_t>::max();
90*d9f75844SAndroid Build Coastguard Worker     }
91*d9f75844SAndroid Build Coastguard Worker   }
92*d9f75844SAndroid Build Coastguard Worker 
93*d9f75844SAndroid Build Coastguard Worker   if (maxRetransmitTime) {
94*d9f75844SAndroid Build Coastguard Worker     if (*maxRetransmitTime < 0) {
95*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_ERROR)
96*d9f75844SAndroid Build Coastguard Worker           << "Accepting maxRetransmitTime < 0 for backwards compatibility";
97*d9f75844SAndroid Build Coastguard Worker       maxRetransmitTime = absl::nullopt;
98*d9f75844SAndroid Build Coastguard Worker     } else if (*maxRetransmitTime > std::numeric_limits<uint16_t>::max()) {
99*d9f75844SAndroid Build Coastguard Worker       maxRetransmitTime = std::numeric_limits<uint16_t>::max();
100*d9f75844SAndroid Build Coastguard Worker     }
101*d9f75844SAndroid Build Coastguard Worker   }
102*d9f75844SAndroid Build Coastguard Worker }
103*d9f75844SAndroid Build Coastguard Worker 
AllocateSid(rtc::SSLRole role,int * sid)104*d9f75844SAndroid Build Coastguard Worker bool SctpSidAllocator::AllocateSid(rtc::SSLRole role, int* sid) {
105*d9f75844SAndroid Build Coastguard Worker   int potential_sid = (role == rtc::SSL_CLIENT) ? 0 : 1;
106*d9f75844SAndroid Build Coastguard Worker   while (!IsSidAvailable(potential_sid)) {
107*d9f75844SAndroid Build Coastguard Worker     potential_sid += 2;
108*d9f75844SAndroid Build Coastguard Worker     if (potential_sid > static_cast<int>(cricket::kMaxSctpSid)) {
109*d9f75844SAndroid Build Coastguard Worker       return false;
110*d9f75844SAndroid Build Coastguard Worker     }
111*d9f75844SAndroid Build Coastguard Worker   }
112*d9f75844SAndroid Build Coastguard Worker 
113*d9f75844SAndroid Build Coastguard Worker   *sid = potential_sid;
114*d9f75844SAndroid Build Coastguard Worker   used_sids_.insert(potential_sid);
115*d9f75844SAndroid Build Coastguard Worker   return true;
116*d9f75844SAndroid Build Coastguard Worker }
117*d9f75844SAndroid Build Coastguard Worker 
ReserveSid(int sid)118*d9f75844SAndroid Build Coastguard Worker bool SctpSidAllocator::ReserveSid(int sid) {
119*d9f75844SAndroid Build Coastguard Worker   if (!IsSidAvailable(sid)) {
120*d9f75844SAndroid Build Coastguard Worker     return false;
121*d9f75844SAndroid Build Coastguard Worker   }
122*d9f75844SAndroid Build Coastguard Worker   used_sids_.insert(sid);
123*d9f75844SAndroid Build Coastguard Worker   return true;
124*d9f75844SAndroid Build Coastguard Worker }
125*d9f75844SAndroid Build Coastguard Worker 
ReleaseSid(int sid)126*d9f75844SAndroid Build Coastguard Worker void SctpSidAllocator::ReleaseSid(int sid) {
127*d9f75844SAndroid Build Coastguard Worker   auto it = used_sids_.find(sid);
128*d9f75844SAndroid Build Coastguard Worker   if (it != used_sids_.end()) {
129*d9f75844SAndroid Build Coastguard Worker     used_sids_.erase(it);
130*d9f75844SAndroid Build Coastguard Worker   }
131*d9f75844SAndroid Build Coastguard Worker }
132*d9f75844SAndroid Build Coastguard Worker 
IsSidAvailable(int sid) const133*d9f75844SAndroid Build Coastguard Worker bool SctpSidAllocator::IsSidAvailable(int sid) const {
134*d9f75844SAndroid Build Coastguard Worker   if (sid < static_cast<int>(cricket::kMinSctpSid) ||
135*d9f75844SAndroid Build Coastguard Worker       sid > static_cast<int>(cricket::kMaxSctpSid)) {
136*d9f75844SAndroid Build Coastguard Worker     return false;
137*d9f75844SAndroid Build Coastguard Worker   }
138*d9f75844SAndroid Build Coastguard Worker   return used_sids_.find(sid) == used_sids_.end();
139*d9f75844SAndroid Build Coastguard Worker }
140*d9f75844SAndroid Build Coastguard Worker 
Create(SctpDataChannelControllerInterface * controller,const std::string & label,const InternalDataChannelInit & config,rtc::Thread * signaling_thread,rtc::Thread * network_thread)141*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<SctpDataChannel> SctpDataChannel::Create(
142*d9f75844SAndroid Build Coastguard Worker     SctpDataChannelControllerInterface* controller,
143*d9f75844SAndroid Build Coastguard Worker     const std::string& label,
144*d9f75844SAndroid Build Coastguard Worker     const InternalDataChannelInit& config,
145*d9f75844SAndroid Build Coastguard Worker     rtc::Thread* signaling_thread,
146*d9f75844SAndroid Build Coastguard Worker     rtc::Thread* network_thread) {
147*d9f75844SAndroid Build Coastguard Worker   auto channel = rtc::make_ref_counted<SctpDataChannel>(
148*d9f75844SAndroid Build Coastguard Worker       config, controller, label, signaling_thread, network_thread);
149*d9f75844SAndroid Build Coastguard Worker   if (!channel->Init()) {
150*d9f75844SAndroid Build Coastguard Worker     return nullptr;
151*d9f75844SAndroid Build Coastguard Worker   }
152*d9f75844SAndroid Build Coastguard Worker   return channel;
153*d9f75844SAndroid Build Coastguard Worker }
154*d9f75844SAndroid Build Coastguard Worker 
155*d9f75844SAndroid Build Coastguard Worker // static
CreateProxy(rtc::scoped_refptr<SctpDataChannel> channel)156*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<DataChannelInterface> SctpDataChannel::CreateProxy(
157*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<SctpDataChannel> channel) {
158*d9f75844SAndroid Build Coastguard Worker   // TODO(bugs.webrtc.org/11547): incorporate the network thread in the proxy.
159*d9f75844SAndroid Build Coastguard Worker   auto* signaling_thread = channel->signaling_thread_;
160*d9f75844SAndroid Build Coastguard Worker   return DataChannelProxy::Create(signaling_thread, std::move(channel));
161*d9f75844SAndroid Build Coastguard Worker }
162*d9f75844SAndroid Build Coastguard Worker 
SctpDataChannel(const InternalDataChannelInit & config,SctpDataChannelControllerInterface * controller,const std::string & label,rtc::Thread * signaling_thread,rtc::Thread * network_thread)163*d9f75844SAndroid Build Coastguard Worker SctpDataChannel::SctpDataChannel(const InternalDataChannelInit& config,
164*d9f75844SAndroid Build Coastguard Worker                                  SctpDataChannelControllerInterface* controller,
165*d9f75844SAndroid Build Coastguard Worker                                  const std::string& label,
166*d9f75844SAndroid Build Coastguard Worker                                  rtc::Thread* signaling_thread,
167*d9f75844SAndroid Build Coastguard Worker                                  rtc::Thread* network_thread)
168*d9f75844SAndroid Build Coastguard Worker     : signaling_thread_(signaling_thread),
169*d9f75844SAndroid Build Coastguard Worker       network_thread_(network_thread),
170*d9f75844SAndroid Build Coastguard Worker       internal_id_(GenerateUniqueId()),
171*d9f75844SAndroid Build Coastguard Worker       label_(label),
172*d9f75844SAndroid Build Coastguard Worker       config_(config),
173*d9f75844SAndroid Build Coastguard Worker       observer_(nullptr),
174*d9f75844SAndroid Build Coastguard Worker       controller_(controller) {
175*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
176*d9f75844SAndroid Build Coastguard Worker   RTC_UNUSED(network_thread_);
177*d9f75844SAndroid Build Coastguard Worker }
178*d9f75844SAndroid Build Coastguard Worker 
DetachFromController()179*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::DetachFromController() {
180*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
181*d9f75844SAndroid Build Coastguard Worker   controller_detached_ = true;
182*d9f75844SAndroid Build Coastguard Worker }
183*d9f75844SAndroid Build Coastguard Worker 
Init()184*d9f75844SAndroid Build Coastguard Worker bool SctpDataChannel::Init() {
185*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
186*d9f75844SAndroid Build Coastguard Worker   if (config_.id < -1 ||
187*d9f75844SAndroid Build Coastguard Worker       (config_.maxRetransmits && *config_.maxRetransmits < 0) ||
188*d9f75844SAndroid Build Coastguard Worker       (config_.maxRetransmitTime && *config_.maxRetransmitTime < 0)) {
189*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Failed to initialize the SCTP data channel due to "
190*d9f75844SAndroid Build Coastguard Worker                          "invalid DataChannelInit.";
191*d9f75844SAndroid Build Coastguard Worker     return false;
192*d9f75844SAndroid Build Coastguard Worker   }
193*d9f75844SAndroid Build Coastguard Worker   if (config_.maxRetransmits && config_.maxRetransmitTime) {
194*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR)
195*d9f75844SAndroid Build Coastguard Worker         << "maxRetransmits and maxRetransmitTime should not be both set.";
196*d9f75844SAndroid Build Coastguard Worker     return false;
197*d9f75844SAndroid Build Coastguard Worker   }
198*d9f75844SAndroid Build Coastguard Worker 
199*d9f75844SAndroid Build Coastguard Worker   switch (config_.open_handshake_role) {
200*d9f75844SAndroid Build Coastguard Worker     case webrtc::InternalDataChannelInit::kNone:  // pre-negotiated
201*d9f75844SAndroid Build Coastguard Worker       handshake_state_ = kHandshakeReady;
202*d9f75844SAndroid Build Coastguard Worker       break;
203*d9f75844SAndroid Build Coastguard Worker     case webrtc::InternalDataChannelInit::kOpener:
204*d9f75844SAndroid Build Coastguard Worker       handshake_state_ = kHandshakeShouldSendOpen;
205*d9f75844SAndroid Build Coastguard Worker       break;
206*d9f75844SAndroid Build Coastguard Worker     case webrtc::InternalDataChannelInit::kAcker:
207*d9f75844SAndroid Build Coastguard Worker       handshake_state_ = kHandshakeShouldSendAck;
208*d9f75844SAndroid Build Coastguard Worker       break;
209*d9f75844SAndroid Build Coastguard Worker   }
210*d9f75844SAndroid Build Coastguard Worker 
211*d9f75844SAndroid Build Coastguard Worker   // Try to connect to the transport in case the transport channel already
212*d9f75844SAndroid Build Coastguard Worker   // exists.
213*d9f75844SAndroid Build Coastguard Worker   OnTransportChannelCreated();
214*d9f75844SAndroid Build Coastguard Worker 
215*d9f75844SAndroid Build Coastguard Worker   // Checks if the transport is ready to send because the initial channel
216*d9f75844SAndroid Build Coastguard Worker   // ready signal may have been sent before the DataChannel creation.
217*d9f75844SAndroid Build Coastguard Worker   // This has to be done async because the upper layer objects (e.g.
218*d9f75844SAndroid Build Coastguard Worker   // Chrome glue and WebKit) are not wired up properly until after this
219*d9f75844SAndroid Build Coastguard Worker   // function returns.
220*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!controller_detached_);
221*d9f75844SAndroid Build Coastguard Worker   if (controller_->ReadyToSendData()) {
222*d9f75844SAndroid Build Coastguard Worker     AddRef();
223*d9f75844SAndroid Build Coastguard Worker     absl::Cleanup release = [this] { Release(); };
224*d9f75844SAndroid Build Coastguard Worker     rtc::Thread::Current()->PostTask([this, release = std::move(release)] {
225*d9f75844SAndroid Build Coastguard Worker       RTC_DCHECK_RUN_ON(signaling_thread_);
226*d9f75844SAndroid Build Coastguard Worker       if (state_ != kClosed)
227*d9f75844SAndroid Build Coastguard Worker         OnTransportReady(true);
228*d9f75844SAndroid Build Coastguard Worker     });
229*d9f75844SAndroid Build Coastguard Worker   }
230*d9f75844SAndroid Build Coastguard Worker 
231*d9f75844SAndroid Build Coastguard Worker   return true;
232*d9f75844SAndroid Build Coastguard Worker }
233*d9f75844SAndroid Build Coastguard Worker 
~SctpDataChannel()234*d9f75844SAndroid Build Coastguard Worker SctpDataChannel::~SctpDataChannel() {
235*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
236*d9f75844SAndroid Build Coastguard Worker }
237*d9f75844SAndroid Build Coastguard Worker 
RegisterObserver(DataChannelObserver * observer)238*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::RegisterObserver(DataChannelObserver* observer) {
239*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
240*d9f75844SAndroid Build Coastguard Worker   observer_ = observer;
241*d9f75844SAndroid Build Coastguard Worker   DeliverQueuedReceivedData();
242*d9f75844SAndroid Build Coastguard Worker }
243*d9f75844SAndroid Build Coastguard Worker 
UnregisterObserver()244*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::UnregisterObserver() {
245*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
246*d9f75844SAndroid Build Coastguard Worker   observer_ = nullptr;
247*d9f75844SAndroid Build Coastguard Worker }
248*d9f75844SAndroid Build Coastguard Worker 
reliable() const249*d9f75844SAndroid Build Coastguard Worker bool SctpDataChannel::reliable() const {
250*d9f75844SAndroid Build Coastguard Worker   // May be called on any thread.
251*d9f75844SAndroid Build Coastguard Worker   return !config_.maxRetransmits && !config_.maxRetransmitTime;
252*d9f75844SAndroid Build Coastguard Worker }
253*d9f75844SAndroid Build Coastguard Worker 
buffered_amount() const254*d9f75844SAndroid Build Coastguard Worker uint64_t SctpDataChannel::buffered_amount() const {
255*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
256*d9f75844SAndroid Build Coastguard Worker   return queued_send_data_.byte_count();
257*d9f75844SAndroid Build Coastguard Worker }
258*d9f75844SAndroid Build Coastguard Worker 
Close()259*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::Close() {
260*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
261*d9f75844SAndroid Build Coastguard Worker   if (state_ == kClosing || state_ == kClosed)
262*d9f75844SAndroid Build Coastguard Worker     return;
263*d9f75844SAndroid Build Coastguard Worker   SetState(kClosing);
264*d9f75844SAndroid Build Coastguard Worker   // Will send queued data before beginning the underlying closing procedure.
265*d9f75844SAndroid Build Coastguard Worker   UpdateState();
266*d9f75844SAndroid Build Coastguard Worker }
267*d9f75844SAndroid Build Coastguard Worker 
state() const268*d9f75844SAndroid Build Coastguard Worker SctpDataChannel::DataState SctpDataChannel::state() const {
269*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
270*d9f75844SAndroid Build Coastguard Worker   return state_;
271*d9f75844SAndroid Build Coastguard Worker }
272*d9f75844SAndroid Build Coastguard Worker 
error() const273*d9f75844SAndroid Build Coastguard Worker RTCError SctpDataChannel::error() const {
274*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
275*d9f75844SAndroid Build Coastguard Worker   return error_;
276*d9f75844SAndroid Build Coastguard Worker }
277*d9f75844SAndroid Build Coastguard Worker 
messages_sent() const278*d9f75844SAndroid Build Coastguard Worker uint32_t SctpDataChannel::messages_sent() const {
279*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
280*d9f75844SAndroid Build Coastguard Worker   return messages_sent_;
281*d9f75844SAndroid Build Coastguard Worker }
282*d9f75844SAndroid Build Coastguard Worker 
bytes_sent() const283*d9f75844SAndroid Build Coastguard Worker uint64_t SctpDataChannel::bytes_sent() const {
284*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
285*d9f75844SAndroid Build Coastguard Worker   return bytes_sent_;
286*d9f75844SAndroid Build Coastguard Worker }
287*d9f75844SAndroid Build Coastguard Worker 
messages_received() const288*d9f75844SAndroid Build Coastguard Worker uint32_t SctpDataChannel::messages_received() const {
289*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
290*d9f75844SAndroid Build Coastguard Worker   return messages_received_;
291*d9f75844SAndroid Build Coastguard Worker }
292*d9f75844SAndroid Build Coastguard Worker 
bytes_received() const293*d9f75844SAndroid Build Coastguard Worker uint64_t SctpDataChannel::bytes_received() const {
294*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
295*d9f75844SAndroid Build Coastguard Worker   return bytes_received_;
296*d9f75844SAndroid Build Coastguard Worker }
297*d9f75844SAndroid Build Coastguard Worker 
Send(const DataBuffer & buffer)298*d9f75844SAndroid Build Coastguard Worker bool SctpDataChannel::Send(const DataBuffer& buffer) {
299*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
300*d9f75844SAndroid Build Coastguard Worker   // TODO(bugs.webrtc.org/11547): Expect this method to be called on the network
301*d9f75844SAndroid Build Coastguard Worker   // thread. Bring buffer management etc to the network thread and keep the
302*d9f75844SAndroid Build Coastguard Worker   // operational state management on the signaling thread.
303*d9f75844SAndroid Build Coastguard Worker 
304*d9f75844SAndroid Build Coastguard Worker   if (state_ != kOpen) {
305*d9f75844SAndroid Build Coastguard Worker     return false;
306*d9f75844SAndroid Build Coastguard Worker   }
307*d9f75844SAndroid Build Coastguard Worker 
308*d9f75844SAndroid Build Coastguard Worker   // If the queue is non-empty, we're waiting for SignalReadyToSend,
309*d9f75844SAndroid Build Coastguard Worker   // so just add to the end of the queue and keep waiting.
310*d9f75844SAndroid Build Coastguard Worker   if (!queued_send_data_.Empty()) {
311*d9f75844SAndroid Build Coastguard Worker     if (!QueueSendDataMessage(buffer)) {
312*d9f75844SAndroid Build Coastguard Worker       // Queue is full
313*d9f75844SAndroid Build Coastguard Worker       return false;
314*d9f75844SAndroid Build Coastguard Worker     }
315*d9f75844SAndroid Build Coastguard Worker     return true;
316*d9f75844SAndroid Build Coastguard Worker   }
317*d9f75844SAndroid Build Coastguard Worker 
318*d9f75844SAndroid Build Coastguard Worker   SendDataMessage(buffer, true);
319*d9f75844SAndroid Build Coastguard Worker 
320*d9f75844SAndroid Build Coastguard Worker   // Always return true for SCTP DataChannel per the spec.
321*d9f75844SAndroid Build Coastguard Worker   return true;
322*d9f75844SAndroid Build Coastguard Worker }
323*d9f75844SAndroid Build Coastguard Worker 
SetSctpSid(int sid)324*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::SetSctpSid(int sid) {
325*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
326*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_LT(config_.id, 0);
327*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GE(sid, 0);
328*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_NE(handshake_state_, kHandshakeWaitingForAck);
329*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_EQ(state_, kConnecting);
330*d9f75844SAndroid Build Coastguard Worker 
331*d9f75844SAndroid Build Coastguard Worker   if (config_.id == sid) {
332*d9f75844SAndroid Build Coastguard Worker     return;
333*d9f75844SAndroid Build Coastguard Worker   }
334*d9f75844SAndroid Build Coastguard Worker 
335*d9f75844SAndroid Build Coastguard Worker   const_cast<InternalDataChannelInit&>(config_).id = sid;
336*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!controller_detached_);
337*d9f75844SAndroid Build Coastguard Worker   controller_->AddSctpDataStream(sid);
338*d9f75844SAndroid Build Coastguard Worker }
339*d9f75844SAndroid Build Coastguard Worker 
OnClosingProcedureStartedRemotely(int sid)340*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::OnClosingProcedureStartedRemotely(int sid) {
341*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
342*d9f75844SAndroid Build Coastguard Worker   if (sid == config_.id && state_ != kClosing && state_ != kClosed) {
343*d9f75844SAndroid Build Coastguard Worker     // Don't bother sending queued data since the side that initiated the
344*d9f75844SAndroid Build Coastguard Worker     // closure wouldn't receive it anyway. See crbug.com/559394 for a lengthy
345*d9f75844SAndroid Build Coastguard Worker     // discussion about this.
346*d9f75844SAndroid Build Coastguard Worker     queued_send_data_.Clear();
347*d9f75844SAndroid Build Coastguard Worker     queued_control_data_.Clear();
348*d9f75844SAndroid Build Coastguard Worker     // Just need to change state to kClosing, SctpTransport will handle the
349*d9f75844SAndroid Build Coastguard Worker     // rest of the closing procedure and OnClosingProcedureComplete will be
350*d9f75844SAndroid Build Coastguard Worker     // called later.
351*d9f75844SAndroid Build Coastguard Worker     started_closing_procedure_ = true;
352*d9f75844SAndroid Build Coastguard Worker     SetState(kClosing);
353*d9f75844SAndroid Build Coastguard Worker   }
354*d9f75844SAndroid Build Coastguard Worker }
355*d9f75844SAndroid Build Coastguard Worker 
OnClosingProcedureComplete(int sid)356*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::OnClosingProcedureComplete(int sid) {
357*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
358*d9f75844SAndroid Build Coastguard Worker   if (sid == config_.id) {
359*d9f75844SAndroid Build Coastguard Worker     // If the closing procedure is complete, we should have finished sending
360*d9f75844SAndroid Build Coastguard Worker     // all pending data and transitioned to kClosing already.
361*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK_EQ(state_, kClosing);
362*d9f75844SAndroid Build Coastguard Worker     RTC_DCHECK(queued_send_data_.Empty());
363*d9f75844SAndroid Build Coastguard Worker     DisconnectFromTransport();
364*d9f75844SAndroid Build Coastguard Worker     SetState(kClosed);
365*d9f75844SAndroid Build Coastguard Worker   }
366*d9f75844SAndroid Build Coastguard Worker }
367*d9f75844SAndroid Build Coastguard Worker 
OnTransportChannelCreated()368*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::OnTransportChannelCreated() {
369*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
370*d9f75844SAndroid Build Coastguard Worker   if (controller_detached_) {
371*d9f75844SAndroid Build Coastguard Worker     return;
372*d9f75844SAndroid Build Coastguard Worker   }
373*d9f75844SAndroid Build Coastguard Worker   if (!connected_to_transport_) {
374*d9f75844SAndroid Build Coastguard Worker     connected_to_transport_ = controller_->ConnectDataChannel(this);
375*d9f75844SAndroid Build Coastguard Worker   }
376*d9f75844SAndroid Build Coastguard Worker   // The sid may have been unassigned when controller_->ConnectDataChannel was
377*d9f75844SAndroid Build Coastguard Worker   // done. So always add the streams even if connected_to_transport_ is true.
378*d9f75844SAndroid Build Coastguard Worker   if (config_.id >= 0) {
379*d9f75844SAndroid Build Coastguard Worker     controller_->AddSctpDataStream(config_.id);
380*d9f75844SAndroid Build Coastguard Worker   }
381*d9f75844SAndroid Build Coastguard Worker }
382*d9f75844SAndroid Build Coastguard Worker 
OnTransportChannelClosed(RTCError error)383*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::OnTransportChannelClosed(RTCError error) {
384*d9f75844SAndroid Build Coastguard Worker   // The SctpTransport is unusable, which could come from multiplie reasons:
385*d9f75844SAndroid Build Coastguard Worker   // - the SCTP m= section was rejected
386*d9f75844SAndroid Build Coastguard Worker   // - the DTLS transport is closed
387*d9f75844SAndroid Build Coastguard Worker   // - the SCTP transport is closed
388*d9f75844SAndroid Build Coastguard Worker   CloseAbruptlyWithError(std::move(error));
389*d9f75844SAndroid Build Coastguard Worker }
390*d9f75844SAndroid Build Coastguard Worker 
GetStats() const391*d9f75844SAndroid Build Coastguard Worker DataChannelStats SctpDataChannel::GetStats() const {
392*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
393*d9f75844SAndroid Build Coastguard Worker   DataChannelStats stats{internal_id_,        id(),         label(),
394*d9f75844SAndroid Build Coastguard Worker                          protocol(),          state(),      messages_sent(),
395*d9f75844SAndroid Build Coastguard Worker                          messages_received(), bytes_sent(), bytes_received()};
396*d9f75844SAndroid Build Coastguard Worker   return stats;
397*d9f75844SAndroid Build Coastguard Worker }
398*d9f75844SAndroid Build Coastguard Worker 
OnDataReceived(const cricket::ReceiveDataParams & params,const rtc::CopyOnWriteBuffer & payload)399*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::OnDataReceived(const cricket::ReceiveDataParams& params,
400*d9f75844SAndroid Build Coastguard Worker                                      const rtc::CopyOnWriteBuffer& payload) {
401*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
402*d9f75844SAndroid Build Coastguard Worker   if (params.sid != config_.id) {
403*d9f75844SAndroid Build Coastguard Worker     return;
404*d9f75844SAndroid Build Coastguard Worker   }
405*d9f75844SAndroid Build Coastguard Worker 
406*d9f75844SAndroid Build Coastguard Worker   if (params.type == DataMessageType::kControl) {
407*d9f75844SAndroid Build Coastguard Worker     if (handshake_state_ != kHandshakeWaitingForAck) {
408*d9f75844SAndroid Build Coastguard Worker       // Ignore it if we are not expecting an ACK message.
409*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_WARNING)
410*d9f75844SAndroid Build Coastguard Worker           << "DataChannel received unexpected CONTROL message, sid = "
411*d9f75844SAndroid Build Coastguard Worker           << params.sid;
412*d9f75844SAndroid Build Coastguard Worker       return;
413*d9f75844SAndroid Build Coastguard Worker     }
414*d9f75844SAndroid Build Coastguard Worker     if (ParseDataChannelOpenAckMessage(payload)) {
415*d9f75844SAndroid Build Coastguard Worker       // We can send unordered as soon as we receive the ACK message.
416*d9f75844SAndroid Build Coastguard Worker       handshake_state_ = kHandshakeReady;
417*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_INFO) << "DataChannel received OPEN_ACK message, sid = "
418*d9f75844SAndroid Build Coastguard Worker                        << params.sid;
419*d9f75844SAndroid Build Coastguard Worker     } else {
420*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_WARNING)
421*d9f75844SAndroid Build Coastguard Worker           << "DataChannel failed to parse OPEN_ACK message, sid = "
422*d9f75844SAndroid Build Coastguard Worker           << params.sid;
423*d9f75844SAndroid Build Coastguard Worker     }
424*d9f75844SAndroid Build Coastguard Worker     return;
425*d9f75844SAndroid Build Coastguard Worker   }
426*d9f75844SAndroid Build Coastguard Worker 
427*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(params.type == DataMessageType::kBinary ||
428*d9f75844SAndroid Build Coastguard Worker              params.type == DataMessageType::kText);
429*d9f75844SAndroid Build Coastguard Worker 
430*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_VERBOSE) << "DataChannel received DATA message, sid = "
431*d9f75844SAndroid Build Coastguard Worker                       << params.sid;
432*d9f75844SAndroid Build Coastguard Worker   // We can send unordered as soon as we receive any DATA message since the
433*d9f75844SAndroid Build Coastguard Worker   // remote side must have received the OPEN (and old clients do not send
434*d9f75844SAndroid Build Coastguard Worker   // OPEN_ACK).
435*d9f75844SAndroid Build Coastguard Worker   if (handshake_state_ == kHandshakeWaitingForAck) {
436*d9f75844SAndroid Build Coastguard Worker     handshake_state_ = kHandshakeReady;
437*d9f75844SAndroid Build Coastguard Worker   }
438*d9f75844SAndroid Build Coastguard Worker 
439*d9f75844SAndroid Build Coastguard Worker   bool binary = (params.type == webrtc::DataMessageType::kBinary);
440*d9f75844SAndroid Build Coastguard Worker   auto buffer = std::make_unique<DataBuffer>(payload, binary);
441*d9f75844SAndroid Build Coastguard Worker   if (state_ == kOpen && observer_) {
442*d9f75844SAndroid Build Coastguard Worker     ++messages_received_;
443*d9f75844SAndroid Build Coastguard Worker     bytes_received_ += buffer->size();
444*d9f75844SAndroid Build Coastguard Worker     observer_->OnMessage(*buffer.get());
445*d9f75844SAndroid Build Coastguard Worker   } else {
446*d9f75844SAndroid Build Coastguard Worker     if (queued_received_data_.byte_count() + payload.size() >
447*d9f75844SAndroid Build Coastguard Worker         kMaxQueuedReceivedDataBytes) {
448*d9f75844SAndroid Build Coastguard Worker       RTC_LOG(LS_ERROR) << "Queued received data exceeds the max buffer size.";
449*d9f75844SAndroid Build Coastguard Worker 
450*d9f75844SAndroid Build Coastguard Worker       queued_received_data_.Clear();
451*d9f75844SAndroid Build Coastguard Worker       CloseAbruptlyWithError(
452*d9f75844SAndroid Build Coastguard Worker           RTCError(RTCErrorType::RESOURCE_EXHAUSTED,
453*d9f75844SAndroid Build Coastguard Worker                    "Queued received data exceeds the max buffer size."));
454*d9f75844SAndroid Build Coastguard Worker 
455*d9f75844SAndroid Build Coastguard Worker       return;
456*d9f75844SAndroid Build Coastguard Worker     }
457*d9f75844SAndroid Build Coastguard Worker     queued_received_data_.PushBack(std::move(buffer));
458*d9f75844SAndroid Build Coastguard Worker   }
459*d9f75844SAndroid Build Coastguard Worker }
460*d9f75844SAndroid Build Coastguard Worker 
OnTransportReady(bool writable)461*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::OnTransportReady(bool writable) {
462*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
463*d9f75844SAndroid Build Coastguard Worker 
464*d9f75844SAndroid Build Coastguard Worker   writable_ = writable;
465*d9f75844SAndroid Build Coastguard Worker   if (!writable) {
466*d9f75844SAndroid Build Coastguard Worker     return;
467*d9f75844SAndroid Build Coastguard Worker   }
468*d9f75844SAndroid Build Coastguard Worker 
469*d9f75844SAndroid Build Coastguard Worker   SendQueuedControlMessages();
470*d9f75844SAndroid Build Coastguard Worker   SendQueuedDataMessages();
471*d9f75844SAndroid Build Coastguard Worker 
472*d9f75844SAndroid Build Coastguard Worker   UpdateState();
473*d9f75844SAndroid Build Coastguard Worker }
474*d9f75844SAndroid Build Coastguard Worker 
CloseAbruptlyWithError(RTCError error)475*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::CloseAbruptlyWithError(RTCError error) {
476*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
477*d9f75844SAndroid Build Coastguard Worker 
478*d9f75844SAndroid Build Coastguard Worker   if (state_ == kClosed) {
479*d9f75844SAndroid Build Coastguard Worker     return;
480*d9f75844SAndroid Build Coastguard Worker   }
481*d9f75844SAndroid Build Coastguard Worker 
482*d9f75844SAndroid Build Coastguard Worker   if (connected_to_transport_) {
483*d9f75844SAndroid Build Coastguard Worker     DisconnectFromTransport();
484*d9f75844SAndroid Build Coastguard Worker   }
485*d9f75844SAndroid Build Coastguard Worker 
486*d9f75844SAndroid Build Coastguard Worker   // Closing abruptly means any queued data gets thrown away.
487*d9f75844SAndroid Build Coastguard Worker   queued_send_data_.Clear();
488*d9f75844SAndroid Build Coastguard Worker   queued_control_data_.Clear();
489*d9f75844SAndroid Build Coastguard Worker 
490*d9f75844SAndroid Build Coastguard Worker   // Still go to "kClosing" before "kClosed", since observers may be expecting
491*d9f75844SAndroid Build Coastguard Worker   // that.
492*d9f75844SAndroid Build Coastguard Worker   SetState(kClosing);
493*d9f75844SAndroid Build Coastguard Worker   error_ = std::move(error);
494*d9f75844SAndroid Build Coastguard Worker   SetState(kClosed);
495*d9f75844SAndroid Build Coastguard Worker }
496*d9f75844SAndroid Build Coastguard Worker 
CloseAbruptlyWithDataChannelFailure(const std::string & message)497*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::CloseAbruptlyWithDataChannelFailure(
498*d9f75844SAndroid Build Coastguard Worker     const std::string& message) {
499*d9f75844SAndroid Build Coastguard Worker   RTCError error(RTCErrorType::OPERATION_ERROR_WITH_DATA, message);
500*d9f75844SAndroid Build Coastguard Worker   error.set_error_detail(RTCErrorDetailType::DATA_CHANNEL_FAILURE);
501*d9f75844SAndroid Build Coastguard Worker   CloseAbruptlyWithError(std::move(error));
502*d9f75844SAndroid Build Coastguard Worker }
503*d9f75844SAndroid Build Coastguard Worker 
UpdateState()504*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::UpdateState() {
505*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
506*d9f75844SAndroid Build Coastguard Worker   // UpdateState determines what to do from a few state variables. Include
507*d9f75844SAndroid Build Coastguard Worker   // all conditions required for each state transition here for
508*d9f75844SAndroid Build Coastguard Worker   // clarity. OnTransportReady(true) will send any queued data and then invoke
509*d9f75844SAndroid Build Coastguard Worker   // UpdateState().
510*d9f75844SAndroid Build Coastguard Worker 
511*d9f75844SAndroid Build Coastguard Worker   switch (state_) {
512*d9f75844SAndroid Build Coastguard Worker     case kConnecting: {
513*d9f75844SAndroid Build Coastguard Worker       if (connected_to_transport_) {
514*d9f75844SAndroid Build Coastguard Worker         if (handshake_state_ == kHandshakeShouldSendOpen) {
515*d9f75844SAndroid Build Coastguard Worker           rtc::CopyOnWriteBuffer payload;
516*d9f75844SAndroid Build Coastguard Worker           WriteDataChannelOpenMessage(label_, config_, &payload);
517*d9f75844SAndroid Build Coastguard Worker           SendControlMessage(payload);
518*d9f75844SAndroid Build Coastguard Worker         } else if (handshake_state_ == kHandshakeShouldSendAck) {
519*d9f75844SAndroid Build Coastguard Worker           rtc::CopyOnWriteBuffer payload;
520*d9f75844SAndroid Build Coastguard Worker           WriteDataChannelOpenAckMessage(&payload);
521*d9f75844SAndroid Build Coastguard Worker           SendControlMessage(payload);
522*d9f75844SAndroid Build Coastguard Worker         }
523*d9f75844SAndroid Build Coastguard Worker         if (writable_ && (handshake_state_ == kHandshakeReady ||
524*d9f75844SAndroid Build Coastguard Worker                           handshake_state_ == kHandshakeWaitingForAck)) {
525*d9f75844SAndroid Build Coastguard Worker           SetState(kOpen);
526*d9f75844SAndroid Build Coastguard Worker           // If we have received buffers before the channel got writable.
527*d9f75844SAndroid Build Coastguard Worker           // Deliver them now.
528*d9f75844SAndroid Build Coastguard Worker           DeliverQueuedReceivedData();
529*d9f75844SAndroid Build Coastguard Worker         }
530*d9f75844SAndroid Build Coastguard Worker       }
531*d9f75844SAndroid Build Coastguard Worker       break;
532*d9f75844SAndroid Build Coastguard Worker     }
533*d9f75844SAndroid Build Coastguard Worker     case kOpen: {
534*d9f75844SAndroid Build Coastguard Worker       break;
535*d9f75844SAndroid Build Coastguard Worker     }
536*d9f75844SAndroid Build Coastguard Worker     case kClosing: {
537*d9f75844SAndroid Build Coastguard Worker       // Wait for all queued data to be sent before beginning the closing
538*d9f75844SAndroid Build Coastguard Worker       // procedure.
539*d9f75844SAndroid Build Coastguard Worker       if (queued_send_data_.Empty() && queued_control_data_.Empty()) {
540*d9f75844SAndroid Build Coastguard Worker         // For SCTP data channels, we need to wait for the closing procedure
541*d9f75844SAndroid Build Coastguard Worker         // to complete; after calling RemoveSctpDataStream,
542*d9f75844SAndroid Build Coastguard Worker         // OnClosingProcedureComplete will end up called asynchronously
543*d9f75844SAndroid Build Coastguard Worker         // afterwards.
544*d9f75844SAndroid Build Coastguard Worker         if (connected_to_transport_ && !started_closing_procedure_ &&
545*d9f75844SAndroid Build Coastguard Worker             !controller_detached_ && config_.id >= 0) {
546*d9f75844SAndroid Build Coastguard Worker           started_closing_procedure_ = true;
547*d9f75844SAndroid Build Coastguard Worker           controller_->RemoveSctpDataStream(config_.id);
548*d9f75844SAndroid Build Coastguard Worker         }
549*d9f75844SAndroid Build Coastguard Worker       }
550*d9f75844SAndroid Build Coastguard Worker       break;
551*d9f75844SAndroid Build Coastguard Worker     }
552*d9f75844SAndroid Build Coastguard Worker     case kClosed:
553*d9f75844SAndroid Build Coastguard Worker       break;
554*d9f75844SAndroid Build Coastguard Worker   }
555*d9f75844SAndroid Build Coastguard Worker }
556*d9f75844SAndroid Build Coastguard Worker 
SetState(DataState state)557*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::SetState(DataState state) {
558*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
559*d9f75844SAndroid Build Coastguard Worker   if (state_ == state) {
560*d9f75844SAndroid Build Coastguard Worker     return;
561*d9f75844SAndroid Build Coastguard Worker   }
562*d9f75844SAndroid Build Coastguard Worker 
563*d9f75844SAndroid Build Coastguard Worker   state_ = state;
564*d9f75844SAndroid Build Coastguard Worker   if (observer_) {
565*d9f75844SAndroid Build Coastguard Worker     observer_->OnStateChange();
566*d9f75844SAndroid Build Coastguard Worker   }
567*d9f75844SAndroid Build Coastguard Worker   if (state_ == kOpen) {
568*d9f75844SAndroid Build Coastguard Worker     SignalOpened(this);
569*d9f75844SAndroid Build Coastguard Worker   } else if (state_ == kClosed) {
570*d9f75844SAndroid Build Coastguard Worker     SignalClosed(this);
571*d9f75844SAndroid Build Coastguard Worker   }
572*d9f75844SAndroid Build Coastguard Worker }
573*d9f75844SAndroid Build Coastguard Worker 
DisconnectFromTransport()574*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::DisconnectFromTransport() {
575*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
576*d9f75844SAndroid Build Coastguard Worker   if (!connected_to_transport_ || controller_detached_)
577*d9f75844SAndroid Build Coastguard Worker     return;
578*d9f75844SAndroid Build Coastguard Worker 
579*d9f75844SAndroid Build Coastguard Worker   controller_->DisconnectDataChannel(this);
580*d9f75844SAndroid Build Coastguard Worker   connected_to_transport_ = false;
581*d9f75844SAndroid Build Coastguard Worker }
582*d9f75844SAndroid Build Coastguard Worker 
DeliverQueuedReceivedData()583*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::DeliverQueuedReceivedData() {
584*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
585*d9f75844SAndroid Build Coastguard Worker   if (!observer_) {
586*d9f75844SAndroid Build Coastguard Worker     return;
587*d9f75844SAndroid Build Coastguard Worker   }
588*d9f75844SAndroid Build Coastguard Worker 
589*d9f75844SAndroid Build Coastguard Worker   while (!queued_received_data_.Empty()) {
590*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<DataBuffer> buffer = queued_received_data_.PopFront();
591*d9f75844SAndroid Build Coastguard Worker     ++messages_received_;
592*d9f75844SAndroid Build Coastguard Worker     bytes_received_ += buffer->size();
593*d9f75844SAndroid Build Coastguard Worker     observer_->OnMessage(*buffer);
594*d9f75844SAndroid Build Coastguard Worker   }
595*d9f75844SAndroid Build Coastguard Worker }
596*d9f75844SAndroid Build Coastguard Worker 
SendQueuedDataMessages()597*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::SendQueuedDataMessages() {
598*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
599*d9f75844SAndroid Build Coastguard Worker   if (queued_send_data_.Empty()) {
600*d9f75844SAndroid Build Coastguard Worker     return;
601*d9f75844SAndroid Build Coastguard Worker   }
602*d9f75844SAndroid Build Coastguard Worker 
603*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(state_ == kOpen || state_ == kClosing);
604*d9f75844SAndroid Build Coastguard Worker 
605*d9f75844SAndroid Build Coastguard Worker   while (!queued_send_data_.Empty()) {
606*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<DataBuffer> buffer = queued_send_data_.PopFront();
607*d9f75844SAndroid Build Coastguard Worker     if (!SendDataMessage(*buffer, false)) {
608*d9f75844SAndroid Build Coastguard Worker       // Return the message to the front of the queue if sending is aborted.
609*d9f75844SAndroid Build Coastguard Worker       queued_send_data_.PushFront(std::move(buffer));
610*d9f75844SAndroid Build Coastguard Worker       break;
611*d9f75844SAndroid Build Coastguard Worker     }
612*d9f75844SAndroid Build Coastguard Worker   }
613*d9f75844SAndroid Build Coastguard Worker }
614*d9f75844SAndroid Build Coastguard Worker 
SendDataMessage(const DataBuffer & buffer,bool queue_if_blocked)615*d9f75844SAndroid Build Coastguard Worker bool SctpDataChannel::SendDataMessage(const DataBuffer& buffer,
616*d9f75844SAndroid Build Coastguard Worker                                       bool queue_if_blocked) {
617*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
618*d9f75844SAndroid Build Coastguard Worker   SendDataParams send_params;
619*d9f75844SAndroid Build Coastguard Worker   if (controller_detached_) {
620*d9f75844SAndroid Build Coastguard Worker     return false;
621*d9f75844SAndroid Build Coastguard Worker   }
622*d9f75844SAndroid Build Coastguard Worker 
623*d9f75844SAndroid Build Coastguard Worker   send_params.ordered = config_.ordered;
624*d9f75844SAndroid Build Coastguard Worker   // Send as ordered if it is still going through OPEN/ACK signaling.
625*d9f75844SAndroid Build Coastguard Worker   if (handshake_state_ != kHandshakeReady && !config_.ordered) {
626*d9f75844SAndroid Build Coastguard Worker     send_params.ordered = true;
627*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_VERBOSE)
628*d9f75844SAndroid Build Coastguard Worker         << "Sending data as ordered for unordered DataChannel "
629*d9f75844SAndroid Build Coastguard Worker            "because the OPEN_ACK message has not been received.";
630*d9f75844SAndroid Build Coastguard Worker   }
631*d9f75844SAndroid Build Coastguard Worker 
632*d9f75844SAndroid Build Coastguard Worker   send_params.max_rtx_count = config_.maxRetransmits;
633*d9f75844SAndroid Build Coastguard Worker   send_params.max_rtx_ms = config_.maxRetransmitTime;
634*d9f75844SAndroid Build Coastguard Worker   send_params.type =
635*d9f75844SAndroid Build Coastguard Worker       buffer.binary ? DataMessageType::kBinary : DataMessageType::kText;
636*d9f75844SAndroid Build Coastguard Worker 
637*d9f75844SAndroid Build Coastguard Worker   cricket::SendDataResult send_result = cricket::SDR_SUCCESS;
638*d9f75844SAndroid Build Coastguard Worker   bool success =
639*d9f75844SAndroid Build Coastguard Worker       controller_->SendData(config_.id, send_params, buffer.data, &send_result);
640*d9f75844SAndroid Build Coastguard Worker 
641*d9f75844SAndroid Build Coastguard Worker   if (success) {
642*d9f75844SAndroid Build Coastguard Worker     ++messages_sent_;
643*d9f75844SAndroid Build Coastguard Worker     bytes_sent_ += buffer.size();
644*d9f75844SAndroid Build Coastguard Worker 
645*d9f75844SAndroid Build Coastguard Worker     if (observer_ && buffer.size() > 0) {
646*d9f75844SAndroid Build Coastguard Worker       observer_->OnBufferedAmountChange(buffer.size());
647*d9f75844SAndroid Build Coastguard Worker     }
648*d9f75844SAndroid Build Coastguard Worker     return true;
649*d9f75844SAndroid Build Coastguard Worker   }
650*d9f75844SAndroid Build Coastguard Worker 
651*d9f75844SAndroid Build Coastguard Worker   if (send_result == cricket::SDR_BLOCK) {
652*d9f75844SAndroid Build Coastguard Worker     if (!queue_if_blocked || QueueSendDataMessage(buffer)) {
653*d9f75844SAndroid Build Coastguard Worker       return false;
654*d9f75844SAndroid Build Coastguard Worker     }
655*d9f75844SAndroid Build Coastguard Worker   }
656*d9f75844SAndroid Build Coastguard Worker   // Close the channel if the error is not SDR_BLOCK, or if queuing the
657*d9f75844SAndroid Build Coastguard Worker   // message failed.
658*d9f75844SAndroid Build Coastguard Worker   RTC_LOG(LS_ERROR) << "Closing the DataChannel due to a failure to send data, "
659*d9f75844SAndroid Build Coastguard Worker                        "send_result = "
660*d9f75844SAndroid Build Coastguard Worker                     << send_result;
661*d9f75844SAndroid Build Coastguard Worker   CloseAbruptlyWithError(
662*d9f75844SAndroid Build Coastguard Worker       RTCError(RTCErrorType::NETWORK_ERROR, "Failure to send data"));
663*d9f75844SAndroid Build Coastguard Worker 
664*d9f75844SAndroid Build Coastguard Worker   return false;
665*d9f75844SAndroid Build Coastguard Worker }
666*d9f75844SAndroid Build Coastguard Worker 
QueueSendDataMessage(const DataBuffer & buffer)667*d9f75844SAndroid Build Coastguard Worker bool SctpDataChannel::QueueSendDataMessage(const DataBuffer& buffer) {
668*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
669*d9f75844SAndroid Build Coastguard Worker   size_t start_buffered_amount = queued_send_data_.byte_count();
670*d9f75844SAndroid Build Coastguard Worker   if (start_buffered_amount + buffer.size() >
671*d9f75844SAndroid Build Coastguard Worker       DataChannelInterface::MaxSendQueueSize()) {
672*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Can't buffer any more data for the data channel.";
673*d9f75844SAndroid Build Coastguard Worker     return false;
674*d9f75844SAndroid Build Coastguard Worker   }
675*d9f75844SAndroid Build Coastguard Worker   queued_send_data_.PushBack(std::make_unique<DataBuffer>(buffer));
676*d9f75844SAndroid Build Coastguard Worker   return true;
677*d9f75844SAndroid Build Coastguard Worker }
678*d9f75844SAndroid Build Coastguard Worker 
SendQueuedControlMessages()679*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::SendQueuedControlMessages() {
680*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
681*d9f75844SAndroid Build Coastguard Worker   PacketQueue control_packets;
682*d9f75844SAndroid Build Coastguard Worker   control_packets.Swap(&queued_control_data_);
683*d9f75844SAndroid Build Coastguard Worker 
684*d9f75844SAndroid Build Coastguard Worker   while (!control_packets.Empty()) {
685*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<DataBuffer> buf = control_packets.PopFront();
686*d9f75844SAndroid Build Coastguard Worker     SendControlMessage(buf->data);
687*d9f75844SAndroid Build Coastguard Worker   }
688*d9f75844SAndroid Build Coastguard Worker }
689*d9f75844SAndroid Build Coastguard Worker 
QueueControlMessage(const rtc::CopyOnWriteBuffer & buffer)690*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::QueueControlMessage(
691*d9f75844SAndroid Build Coastguard Worker     const rtc::CopyOnWriteBuffer& buffer) {
692*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
693*d9f75844SAndroid Build Coastguard Worker   queued_control_data_.PushBack(std::make_unique<DataBuffer>(buffer, true));
694*d9f75844SAndroid Build Coastguard Worker }
695*d9f75844SAndroid Build Coastguard Worker 
SendControlMessage(const rtc::CopyOnWriteBuffer & buffer)696*d9f75844SAndroid Build Coastguard Worker bool SctpDataChannel::SendControlMessage(const rtc::CopyOnWriteBuffer& buffer) {
697*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(signaling_thread_);
698*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(writable_);
699*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GE(config_.id, 0);
700*d9f75844SAndroid Build Coastguard Worker 
701*d9f75844SAndroid Build Coastguard Worker   if (controller_detached_) {
702*d9f75844SAndroid Build Coastguard Worker     return false;
703*d9f75844SAndroid Build Coastguard Worker   }
704*d9f75844SAndroid Build Coastguard Worker   bool is_open_message = handshake_state_ == kHandshakeShouldSendOpen;
705*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!is_open_message || !config_.negotiated);
706*d9f75844SAndroid Build Coastguard Worker 
707*d9f75844SAndroid Build Coastguard Worker   SendDataParams send_params;
708*d9f75844SAndroid Build Coastguard Worker   // Send data as ordered before we receive any message from the remote peer to
709*d9f75844SAndroid Build Coastguard Worker   // make sure the remote peer will not receive any data before it receives the
710*d9f75844SAndroid Build Coastguard Worker   // OPEN message.
711*d9f75844SAndroid Build Coastguard Worker   send_params.ordered = config_.ordered || is_open_message;
712*d9f75844SAndroid Build Coastguard Worker   send_params.type = DataMessageType::kControl;
713*d9f75844SAndroid Build Coastguard Worker 
714*d9f75844SAndroid Build Coastguard Worker   cricket::SendDataResult send_result = cricket::SDR_SUCCESS;
715*d9f75844SAndroid Build Coastguard Worker   bool retval =
716*d9f75844SAndroid Build Coastguard Worker       controller_->SendData(config_.id, send_params, buffer, &send_result);
717*d9f75844SAndroid Build Coastguard Worker   if (retval) {
718*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_VERBOSE) << "Sent CONTROL message on channel " << config_.id;
719*d9f75844SAndroid Build Coastguard Worker 
720*d9f75844SAndroid Build Coastguard Worker     if (handshake_state_ == kHandshakeShouldSendAck) {
721*d9f75844SAndroid Build Coastguard Worker       handshake_state_ = kHandshakeReady;
722*d9f75844SAndroid Build Coastguard Worker     } else if (handshake_state_ == kHandshakeShouldSendOpen) {
723*d9f75844SAndroid Build Coastguard Worker       handshake_state_ = kHandshakeWaitingForAck;
724*d9f75844SAndroid Build Coastguard Worker     }
725*d9f75844SAndroid Build Coastguard Worker   } else if (send_result == cricket::SDR_BLOCK) {
726*d9f75844SAndroid Build Coastguard Worker     QueueControlMessage(buffer);
727*d9f75844SAndroid Build Coastguard Worker   } else {
728*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Closing the DataChannel due to a failure to send"
729*d9f75844SAndroid Build Coastguard Worker                          " the CONTROL message, send_result = "
730*d9f75844SAndroid Build Coastguard Worker                       << send_result;
731*d9f75844SAndroid Build Coastguard Worker     CloseAbruptlyWithError(RTCError(RTCErrorType::NETWORK_ERROR,
732*d9f75844SAndroid Build Coastguard Worker                                     "Failed to send a CONTROL message"));
733*d9f75844SAndroid Build Coastguard Worker   }
734*d9f75844SAndroid Build Coastguard Worker   return retval;
735*d9f75844SAndroid Build Coastguard Worker }
736*d9f75844SAndroid Build Coastguard Worker 
737*d9f75844SAndroid Build Coastguard Worker // static
ResetInternalIdAllocatorForTesting(int new_value)738*d9f75844SAndroid Build Coastguard Worker void SctpDataChannel::ResetInternalIdAllocatorForTesting(int new_value) {
739*d9f75844SAndroid Build Coastguard Worker   g_unique_id = new_value;
740*d9f75844SAndroid Build Coastguard Worker }
741*d9f75844SAndroid Build Coastguard Worker 
DowncastProxiedDataChannelInterfaceToSctpDataChannelForTesting(DataChannelInterface * channel)742*d9f75844SAndroid Build Coastguard Worker SctpDataChannel* DowncastProxiedDataChannelInterfaceToSctpDataChannelForTesting(
743*d9f75844SAndroid Build Coastguard Worker     DataChannelInterface* channel) {
744*d9f75844SAndroid Build Coastguard Worker   return static_cast<SctpDataChannel*>(
745*d9f75844SAndroid Build Coastguard Worker       static_cast<DataChannelProxy*>(channel)->internal());
746*d9f75844SAndroid Build Coastguard Worker }
747*d9f75844SAndroid Build Coastguard Worker 
748*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
749