xref: /aosp_15_r20/external/webrtc/pc/sctp_transport.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright 2018 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_transport.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <utility>
15*d9f75844SAndroid Build Coastguard Worker 
16*d9f75844SAndroid Build Coastguard Worker #include "absl/types/optional.h"
17*d9f75844SAndroid Build Coastguard Worker #include "api/dtls_transport_interface.h"
18*d9f75844SAndroid Build Coastguard Worker #include "api/sequence_checker.h"
19*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
20*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
21*d9f75844SAndroid Build Coastguard Worker 
22*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
23*d9f75844SAndroid Build Coastguard Worker 
SctpTransport(std::unique_ptr<cricket::SctpTransportInternal> internal)24*d9f75844SAndroid Build Coastguard Worker SctpTransport::SctpTransport(
25*d9f75844SAndroid Build Coastguard Worker     std::unique_ptr<cricket::SctpTransportInternal> internal)
26*d9f75844SAndroid Build Coastguard Worker     : owner_thread_(rtc::Thread::Current()),
27*d9f75844SAndroid Build Coastguard Worker       info_(SctpTransportState::kNew),
28*d9f75844SAndroid Build Coastguard Worker       internal_sctp_transport_(std::move(internal)) {
29*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(internal_sctp_transport_.get());
30*d9f75844SAndroid Build Coastguard Worker   internal_sctp_transport_->SetOnConnectedCallback(
31*d9f75844SAndroid Build Coastguard Worker       [this]() { OnAssociationChangeCommunicationUp(); });
32*d9f75844SAndroid Build Coastguard Worker 
33*d9f75844SAndroid Build Coastguard Worker   if (dtls_transport_) {
34*d9f75844SAndroid Build Coastguard Worker     UpdateInformation(SctpTransportState::kConnecting);
35*d9f75844SAndroid Build Coastguard Worker   } else {
36*d9f75844SAndroid Build Coastguard Worker     UpdateInformation(SctpTransportState::kNew);
37*d9f75844SAndroid Build Coastguard Worker   }
38*d9f75844SAndroid Build Coastguard Worker }
39*d9f75844SAndroid Build Coastguard Worker 
~SctpTransport()40*d9f75844SAndroid Build Coastguard Worker SctpTransport::~SctpTransport() {
41*d9f75844SAndroid Build Coastguard Worker   // We depend on the network thread to call Clear() before dropping
42*d9f75844SAndroid Build Coastguard Worker   // its last reference to this object.
43*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(owner_thread_->IsCurrent() || !internal_sctp_transport_);
44*d9f75844SAndroid Build Coastguard Worker }
45*d9f75844SAndroid Build Coastguard Worker 
Information() const46*d9f75844SAndroid Build Coastguard Worker SctpTransportInformation SctpTransport::Information() const {
47*d9f75844SAndroid Build Coastguard Worker   // TODO(tommi): Update PeerConnection::GetSctpTransport to hand out a proxy
48*d9f75844SAndroid Build Coastguard Worker   // to the transport so that we can be sure that methods get called on the
49*d9f75844SAndroid Build Coastguard Worker   // expected thread. Chromium currently calls this method from
50*d9f75844SAndroid Build Coastguard Worker   // TransceiverStateSurfacer.
51*d9f75844SAndroid Build Coastguard Worker   if (!owner_thread_->IsCurrent()) {
52*d9f75844SAndroid Build Coastguard Worker     return owner_thread_->BlockingCall([this] { return Information(); });
53*d9f75844SAndroid Build Coastguard Worker   }
54*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
55*d9f75844SAndroid Build Coastguard Worker   return info_;
56*d9f75844SAndroid Build Coastguard Worker }
57*d9f75844SAndroid Build Coastguard Worker 
RegisterObserver(SctpTransportObserverInterface * observer)58*d9f75844SAndroid Build Coastguard Worker void SctpTransport::RegisterObserver(SctpTransportObserverInterface* observer) {
59*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
60*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(observer);
61*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(!observer_);
62*d9f75844SAndroid Build Coastguard Worker   observer_ = observer;
63*d9f75844SAndroid Build Coastguard Worker }
64*d9f75844SAndroid Build Coastguard Worker 
UnregisterObserver()65*d9f75844SAndroid Build Coastguard Worker void SctpTransport::UnregisterObserver() {
66*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
67*d9f75844SAndroid Build Coastguard Worker   observer_ = nullptr;
68*d9f75844SAndroid Build Coastguard Worker }
69*d9f75844SAndroid Build Coastguard Worker 
OpenChannel(int channel_id)70*d9f75844SAndroid Build Coastguard Worker RTCError SctpTransport::OpenChannel(int channel_id) {
71*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
72*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(internal_sctp_transport_);
73*d9f75844SAndroid Build Coastguard Worker   internal_sctp_transport_->OpenStream(channel_id);
74*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
75*d9f75844SAndroid Build Coastguard Worker }
76*d9f75844SAndroid Build Coastguard Worker 
SendData(int channel_id,const SendDataParams & params,const rtc::CopyOnWriteBuffer & buffer)77*d9f75844SAndroid Build Coastguard Worker RTCError SctpTransport::SendData(int channel_id,
78*d9f75844SAndroid Build Coastguard Worker                                  const SendDataParams& params,
79*d9f75844SAndroid Build Coastguard Worker                                  const rtc::CopyOnWriteBuffer& buffer) {
80*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
81*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(internal_sctp_transport_);
82*d9f75844SAndroid Build Coastguard Worker   cricket::SendDataResult result;
83*d9f75844SAndroid Build Coastguard Worker   internal_sctp_transport_->SendData(channel_id, params, buffer, &result);
84*d9f75844SAndroid Build Coastguard Worker 
85*d9f75844SAndroid Build Coastguard Worker   // TODO(mellem):  See about changing the interfaces to not require mapping
86*d9f75844SAndroid Build Coastguard Worker   // SendDataResult to RTCError and back again.
87*d9f75844SAndroid Build Coastguard Worker   switch (result) {
88*d9f75844SAndroid Build Coastguard Worker     case cricket::SendDataResult::SDR_SUCCESS:
89*d9f75844SAndroid Build Coastguard Worker       return RTCError::OK();
90*d9f75844SAndroid Build Coastguard Worker     case cricket::SendDataResult::SDR_BLOCK:
91*d9f75844SAndroid Build Coastguard Worker       // Send buffer is full.
92*d9f75844SAndroid Build Coastguard Worker       return RTCError(RTCErrorType::RESOURCE_EXHAUSTED);
93*d9f75844SAndroid Build Coastguard Worker     case cricket::SendDataResult::SDR_ERROR:
94*d9f75844SAndroid Build Coastguard Worker       return RTCError(RTCErrorType::NETWORK_ERROR);
95*d9f75844SAndroid Build Coastguard Worker   }
96*d9f75844SAndroid Build Coastguard Worker   return RTCError(RTCErrorType::NETWORK_ERROR);
97*d9f75844SAndroid Build Coastguard Worker }
98*d9f75844SAndroid Build Coastguard Worker 
CloseChannel(int channel_id)99*d9f75844SAndroid Build Coastguard Worker RTCError SctpTransport::CloseChannel(int channel_id) {
100*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
101*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(internal_sctp_transport_);
102*d9f75844SAndroid Build Coastguard Worker   internal_sctp_transport_->ResetStream(channel_id);
103*d9f75844SAndroid Build Coastguard Worker   return RTCError::OK();
104*d9f75844SAndroid Build Coastguard Worker }
105*d9f75844SAndroid Build Coastguard Worker 
SetDataSink(DataChannelSink * sink)106*d9f75844SAndroid Build Coastguard Worker void SctpTransport::SetDataSink(DataChannelSink* sink) {
107*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
108*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(internal_sctp_transport_);
109*d9f75844SAndroid Build Coastguard Worker   internal_sctp_transport_->SetDataChannelSink(sink);
110*d9f75844SAndroid Build Coastguard Worker }
111*d9f75844SAndroid Build Coastguard Worker 
IsReadyToSend() const112*d9f75844SAndroid Build Coastguard Worker bool SctpTransport::IsReadyToSend() const {
113*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
114*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(internal_sctp_transport_);
115*d9f75844SAndroid Build Coastguard Worker   return internal_sctp_transport_->ReadyToSendData();
116*d9f75844SAndroid Build Coastguard Worker }
117*d9f75844SAndroid Build Coastguard Worker 
dtls_transport() const118*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<DtlsTransportInterface> SctpTransport::dtls_transport()
119*d9f75844SAndroid Build Coastguard Worker     const {
120*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
121*d9f75844SAndroid Build Coastguard Worker   return dtls_transport_;
122*d9f75844SAndroid Build Coastguard Worker }
123*d9f75844SAndroid Build Coastguard Worker 
124*d9f75844SAndroid Build Coastguard Worker // Internal functions
Clear()125*d9f75844SAndroid Build Coastguard Worker void SctpTransport::Clear() {
126*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
127*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(internal());
128*d9f75844SAndroid Build Coastguard Worker   // Note that we delete internal_sctp_transport_, but
129*d9f75844SAndroid Build Coastguard Worker   // only drop the reference to dtls_transport_.
130*d9f75844SAndroid Build Coastguard Worker   dtls_transport_ = nullptr;
131*d9f75844SAndroid Build Coastguard Worker   internal_sctp_transport_ = nullptr;
132*d9f75844SAndroid Build Coastguard Worker   UpdateInformation(SctpTransportState::kClosed);
133*d9f75844SAndroid Build Coastguard Worker }
134*d9f75844SAndroid Build Coastguard Worker 
SetDtlsTransport(rtc::scoped_refptr<DtlsTransport> transport)135*d9f75844SAndroid Build Coastguard Worker void SctpTransport::SetDtlsTransport(
136*d9f75844SAndroid Build Coastguard Worker     rtc::scoped_refptr<DtlsTransport> transport) {
137*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
138*d9f75844SAndroid Build Coastguard Worker   SctpTransportState next_state = info_.state();
139*d9f75844SAndroid Build Coastguard Worker   dtls_transport_ = transport;
140*d9f75844SAndroid Build Coastguard Worker   if (internal_sctp_transport_) {
141*d9f75844SAndroid Build Coastguard Worker     if (transport) {
142*d9f75844SAndroid Build Coastguard Worker       internal_sctp_transport_->SetDtlsTransport(transport->internal());
143*d9f75844SAndroid Build Coastguard Worker 
144*d9f75844SAndroid Build Coastguard Worker       transport->internal()->SubscribeDtlsTransportState(
145*d9f75844SAndroid Build Coastguard Worker           [this](cricket::DtlsTransportInternal* transport,
146*d9f75844SAndroid Build Coastguard Worker                  DtlsTransportState state) {
147*d9f75844SAndroid Build Coastguard Worker             OnDtlsStateChange(transport, state);
148*d9f75844SAndroid Build Coastguard Worker           });
149*d9f75844SAndroid Build Coastguard Worker       if (info_.state() == SctpTransportState::kNew) {
150*d9f75844SAndroid Build Coastguard Worker         next_state = SctpTransportState::kConnecting;
151*d9f75844SAndroid Build Coastguard Worker       }
152*d9f75844SAndroid Build Coastguard Worker     } else {
153*d9f75844SAndroid Build Coastguard Worker       internal_sctp_transport_->SetDtlsTransport(nullptr);
154*d9f75844SAndroid Build Coastguard Worker     }
155*d9f75844SAndroid Build Coastguard Worker   }
156*d9f75844SAndroid Build Coastguard Worker 
157*d9f75844SAndroid Build Coastguard Worker   UpdateInformation(next_state);
158*d9f75844SAndroid Build Coastguard Worker }
159*d9f75844SAndroid Build Coastguard Worker 
Start(int local_port,int remote_port,int max_message_size)160*d9f75844SAndroid Build Coastguard Worker void SctpTransport::Start(int local_port,
161*d9f75844SAndroid Build Coastguard Worker                           int remote_port,
162*d9f75844SAndroid Build Coastguard Worker                           int max_message_size) {
163*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
164*d9f75844SAndroid Build Coastguard Worker   info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(),
165*d9f75844SAndroid Build Coastguard Worker                                    max_message_size, info_.MaxChannels());
166*d9f75844SAndroid Build Coastguard Worker 
167*d9f75844SAndroid Build Coastguard Worker   if (!internal()->Start(local_port, remote_port, max_message_size)) {
168*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR) << "Failed to push down SCTP parameters, closing.";
169*d9f75844SAndroid Build Coastguard Worker     UpdateInformation(SctpTransportState::kClosed);
170*d9f75844SAndroid Build Coastguard Worker   }
171*d9f75844SAndroid Build Coastguard Worker }
172*d9f75844SAndroid Build Coastguard Worker 
UpdateInformation(SctpTransportState state)173*d9f75844SAndroid Build Coastguard Worker void SctpTransport::UpdateInformation(SctpTransportState state) {
174*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
175*d9f75844SAndroid Build Coastguard Worker   bool must_send_update = (state != info_.state());
176*d9f75844SAndroid Build Coastguard Worker   // TODO(https://bugs.webrtc.org/10358): Update max channels from internal
177*d9f75844SAndroid Build Coastguard Worker   // SCTP transport when available.
178*d9f75844SAndroid Build Coastguard Worker   if (internal_sctp_transport_) {
179*d9f75844SAndroid Build Coastguard Worker     info_ = SctpTransportInformation(
180*d9f75844SAndroid Build Coastguard Worker         state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
181*d9f75844SAndroid Build Coastguard Worker   } else {
182*d9f75844SAndroid Build Coastguard Worker     info_ = SctpTransportInformation(
183*d9f75844SAndroid Build Coastguard Worker         state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
184*d9f75844SAndroid Build Coastguard Worker   }
185*d9f75844SAndroid Build Coastguard Worker 
186*d9f75844SAndroid Build Coastguard Worker   if (observer_ && must_send_update) {
187*d9f75844SAndroid Build Coastguard Worker     observer_->OnStateChange(info_);
188*d9f75844SAndroid Build Coastguard Worker   }
189*d9f75844SAndroid Build Coastguard Worker }
190*d9f75844SAndroid Build Coastguard Worker 
OnAssociationChangeCommunicationUp()191*d9f75844SAndroid Build Coastguard Worker void SctpTransport::OnAssociationChangeCommunicationUp() {
192*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
193*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK(internal_sctp_transport_);
194*d9f75844SAndroid Build Coastguard Worker   if (internal_sctp_transport_->max_outbound_streams() &&
195*d9f75844SAndroid Build Coastguard Worker       internal_sctp_transport_->max_inbound_streams()) {
196*d9f75844SAndroid Build Coastguard Worker     int max_channels =
197*d9f75844SAndroid Build Coastguard Worker         std::min(*(internal_sctp_transport_->max_outbound_streams()),
198*d9f75844SAndroid Build Coastguard Worker                  *(internal_sctp_transport_->max_inbound_streams()));
199*d9f75844SAndroid Build Coastguard Worker     // Record max channels.
200*d9f75844SAndroid Build Coastguard Worker     info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(),
201*d9f75844SAndroid Build Coastguard Worker                                      info_.MaxMessageSize(), max_channels);
202*d9f75844SAndroid Build Coastguard Worker   }
203*d9f75844SAndroid Build Coastguard Worker 
204*d9f75844SAndroid Build Coastguard Worker   UpdateInformation(SctpTransportState::kConnected);
205*d9f75844SAndroid Build Coastguard Worker }
206*d9f75844SAndroid Build Coastguard Worker 
OnDtlsStateChange(cricket::DtlsTransportInternal * transport,DtlsTransportState state)207*d9f75844SAndroid Build Coastguard Worker void SctpTransport::OnDtlsStateChange(cricket::DtlsTransportInternal* transport,
208*d9f75844SAndroid Build Coastguard Worker                                       DtlsTransportState state) {
209*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_RUN_ON(owner_thread_);
210*d9f75844SAndroid Build Coastguard Worker   RTC_CHECK(transport == dtls_transport_->internal());
211*d9f75844SAndroid Build Coastguard Worker   if (state == DtlsTransportState::kClosed ||
212*d9f75844SAndroid Build Coastguard Worker       state == DtlsTransportState::kFailed) {
213*d9f75844SAndroid Build Coastguard Worker     UpdateInformation(SctpTransportState::kClosed);
214*d9f75844SAndroid Build Coastguard Worker     // TODO(http://bugs.webrtc.org/11090): Close all the data channels
215*d9f75844SAndroid Build Coastguard Worker   }
216*d9f75844SAndroid Build Coastguard Worker }
217*d9f75844SAndroid Build Coastguard Worker 
218*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
219