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/sequence_checker.h"
18 #include "rtc_base/checks.h"
19 #include "rtc_base/location.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_->SignalAssociationChangeCommunicationUp.connect(
31 this, &SctpTransport::OnAssociationChangeCommunicationUp);
32 // TODO(https://bugs.webrtc.org/10360): Add handlers for transport closing.
33
34 if (dtls_transport_) {
35 UpdateInformation(SctpTransportState::kConnecting);
36 } else {
37 UpdateInformation(SctpTransportState::kNew);
38 }
39 }
40
~SctpTransport()41 SctpTransport::~SctpTransport() {
42 // We depend on the network thread to call Clear() before dropping
43 // its last reference to this object.
44 RTC_DCHECK(owner_thread_->IsCurrent() || !internal_sctp_transport_);
45 }
46
Information() const47 SctpTransportInformation SctpTransport::Information() const {
48 // TODO(tommi): Update PeerConnection::GetSctpTransport to hand out a proxy
49 // to the transport so that we can be sure that methods get called on the
50 // expected thread. Chromium currently calls this method from
51 // TransceiverStateSurfacer.
52 if (!owner_thread_->IsCurrent()) {
53 return owner_thread_->Invoke<SctpTransportInformation>(
54 RTC_FROM_HERE, [this] { return Information(); });
55 }
56 RTC_DCHECK_RUN_ON(owner_thread_);
57 return info_;
58 }
59
RegisterObserver(SctpTransportObserverInterface * observer)60 void SctpTransport::RegisterObserver(SctpTransportObserverInterface* observer) {
61 RTC_DCHECK_RUN_ON(owner_thread_);
62 RTC_DCHECK(observer);
63 RTC_DCHECK(!observer_);
64 observer_ = observer;
65 }
66
UnregisterObserver()67 void SctpTransport::UnregisterObserver() {
68 RTC_DCHECK_RUN_ON(owner_thread_);
69 observer_ = nullptr;
70 }
71
dtls_transport() const72 rtc::scoped_refptr<DtlsTransportInterface> SctpTransport::dtls_transport()
73 const {
74 RTC_DCHECK_RUN_ON(owner_thread_);
75 return dtls_transport_;
76 }
77
78 // Internal functions
Clear()79 void SctpTransport::Clear() {
80 RTC_DCHECK_RUN_ON(owner_thread_);
81 RTC_DCHECK(internal());
82 // Note that we delete internal_sctp_transport_, but
83 // only drop the reference to dtls_transport_.
84 dtls_transport_ = nullptr;
85 internal_sctp_transport_ = nullptr;
86 UpdateInformation(SctpTransportState::kClosed);
87 }
88
SetDtlsTransport(rtc::scoped_refptr<DtlsTransport> transport)89 void SctpTransport::SetDtlsTransport(
90 rtc::scoped_refptr<DtlsTransport> transport) {
91 RTC_DCHECK_RUN_ON(owner_thread_);
92 SctpTransportState next_state = info_.state();
93 dtls_transport_ = transport;
94 if (internal_sctp_transport_) {
95 if (transport) {
96 internal_sctp_transport_->SetDtlsTransport(transport->internal());
97
98 transport->internal()->SubscribeDtlsState(
99 [this](cricket::DtlsTransportInternal* transport,
100 cricket::DtlsTransportState state) {
101 OnDtlsStateChange(transport, state);
102 });
103 if (info_.state() == SctpTransportState::kNew) {
104 next_state = SctpTransportState::kConnecting;
105 }
106 } else {
107 internal_sctp_transport_->SetDtlsTransport(nullptr);
108 }
109 }
110
111 UpdateInformation(next_state);
112 }
113
Start(int local_port,int remote_port,int max_message_size)114 void SctpTransport::Start(int local_port,
115 int remote_port,
116 int max_message_size) {
117 RTC_DCHECK_RUN_ON(owner_thread_);
118 info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(),
119 max_message_size, info_.MaxChannels());
120
121 if (!internal()->Start(local_port, remote_port, max_message_size)) {
122 RTC_LOG(LS_ERROR) << "Failed to push down SCTP parameters, closing.";
123 UpdateInformation(SctpTransportState::kClosed);
124 }
125 }
126
UpdateInformation(SctpTransportState state)127 void SctpTransport::UpdateInformation(SctpTransportState state) {
128 RTC_DCHECK_RUN_ON(owner_thread_);
129 bool must_send_update = (state != info_.state());
130 // TODO(https://bugs.webrtc.org/10358): Update max channels from internal
131 // SCTP transport when available.
132 if (internal_sctp_transport_) {
133 info_ = SctpTransportInformation(
134 state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
135 } else {
136 info_ = SctpTransportInformation(
137 state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
138 }
139
140 if (observer_ && must_send_update) {
141 observer_->OnStateChange(info_);
142 }
143 }
144
OnAssociationChangeCommunicationUp()145 void SctpTransport::OnAssociationChangeCommunicationUp() {
146 RTC_DCHECK_RUN_ON(owner_thread_);
147 RTC_DCHECK(internal_sctp_transport_);
148 if (internal_sctp_transport_->max_outbound_streams() &&
149 internal_sctp_transport_->max_inbound_streams()) {
150 int max_channels =
151 std::min(*(internal_sctp_transport_->max_outbound_streams()),
152 *(internal_sctp_transport_->max_inbound_streams()));
153 // Record max channels.
154 info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(),
155 info_.MaxMessageSize(), max_channels);
156 }
157
158 UpdateInformation(SctpTransportState::kConnected);
159 }
160
OnDtlsStateChange(cricket::DtlsTransportInternal * transport,cricket::DtlsTransportState state)161 void SctpTransport::OnDtlsStateChange(cricket::DtlsTransportInternal* transport,
162 cricket::DtlsTransportState state) {
163 RTC_DCHECK_RUN_ON(owner_thread_);
164 RTC_CHECK(transport == dtls_transport_->internal());
165 if (state == cricket::DTLS_TRANSPORT_CLOSED ||
166 state == cricket::DTLS_TRANSPORT_FAILED) {
167 UpdateInformation(SctpTransportState::kClosed);
168 // TODO(http://bugs.webrtc.org/11090): Close all the data channels
169 }
170 }
171
172 } // namespace webrtc
173