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