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