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