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 namespace webrtc {
17
SctpTransport(std::unique_ptr<cricket::SctpTransportInternal> internal)18 SctpTransport::SctpTransport(
19 std::unique_ptr<cricket::SctpTransportInternal> internal)
20 : owner_thread_(rtc::Thread::Current()),
21 info_(SctpTransportState::kNew),
22 internal_sctp_transport_(std::move(internal)) {
23 RTC_DCHECK(internal_sctp_transport_.get());
24 internal_sctp_transport_->SignalAssociationChangeCommunicationUp.connect(
25 this, &SctpTransport::OnAssociationChangeCommunicationUp);
26 // TODO(https://bugs.webrtc.org/10360): Add handlers for transport closing.
27
28 if (dtls_transport_) {
29 UpdateInformation(SctpTransportState::kConnecting);
30 } else {
31 UpdateInformation(SctpTransportState::kNew);
32 }
33 }
34
~SctpTransport()35 SctpTransport::~SctpTransport() {
36 // We depend on the network thread to call Clear() before dropping
37 // its last reference to this object.
38 RTC_DCHECK(owner_thread_->IsCurrent() || !internal_sctp_transport_);
39 }
40
Information() const41 SctpTransportInformation SctpTransport::Information() const {
42 rtc::CritScope scope(&lock_);
43 return info_;
44 }
45
RegisterObserver(SctpTransportObserverInterface * observer)46 void SctpTransport::RegisterObserver(SctpTransportObserverInterface* observer) {
47 RTC_DCHECK_RUN_ON(owner_thread_);
48 RTC_DCHECK(observer);
49 RTC_DCHECK(!observer_);
50 observer_ = observer;
51 }
52
UnregisterObserver()53 void SctpTransport::UnregisterObserver() {
54 RTC_DCHECK_RUN_ON(owner_thread_);
55 observer_ = nullptr;
56 }
57
dtls_transport() const58 rtc::scoped_refptr<DtlsTransportInterface> SctpTransport::dtls_transport()
59 const {
60 RTC_DCHECK_RUN_ON(owner_thread_);
61 return dtls_transport_;
62 }
63
64 // Internal functions
Clear()65 void SctpTransport::Clear() {
66 RTC_DCHECK_RUN_ON(owner_thread_);
67 RTC_DCHECK(internal());
68 {
69 rtc::CritScope scope(&lock_);
70 // Note that we delete internal_sctp_transport_, but
71 // only drop the reference to dtls_transport_.
72 dtls_transport_ = nullptr;
73 internal_sctp_transport_ = nullptr;
74 }
75 UpdateInformation(SctpTransportState::kClosed);
76 }
77
SetDtlsTransport(rtc::scoped_refptr<DtlsTransport> transport)78 void SctpTransport::SetDtlsTransport(
79 rtc::scoped_refptr<DtlsTransport> transport) {
80 RTC_DCHECK_RUN_ON(owner_thread_);
81 SctpTransportState next_state;
82 {
83 rtc::CritScope scope(&lock_);
84 next_state = info_.state();
85 dtls_transport_ = transport;
86 if (internal_sctp_transport_) {
87 if (transport) {
88 internal_sctp_transport_->SetDtlsTransport(transport->internal());
89 transport->internal()->SignalDtlsState.connect(
90 this, &SctpTransport::OnDtlsStateChange);
91 if (info_.state() == SctpTransportState::kNew) {
92 next_state = SctpTransportState::kConnecting;
93 }
94 } else {
95 internal_sctp_transport_->SetDtlsTransport(nullptr);
96 }
97 }
98 }
99 UpdateInformation(next_state);
100 }
101
Start(int local_port,int remote_port,int max_message_size)102 void SctpTransport::Start(int local_port,
103 int remote_port,
104 int max_message_size) {
105 {
106 rtc::CritScope scope(&lock_);
107 // Record max message size on calling thread.
108 info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(),
109 max_message_size, info_.MaxChannels());
110 }
111 if (owner_thread_->IsCurrent()) {
112 if (!internal()->Start(local_port, remote_port, max_message_size)) {
113 RTC_LOG(LS_ERROR) << "Failed to push down SCTP parameters, closing.";
114 UpdateInformation(SctpTransportState::kClosed);
115 }
116 } else {
117 owner_thread_->Invoke<void>(
118 RTC_FROM_HERE, rtc::Bind(&SctpTransport::Start, this, local_port,
119 remote_port, max_message_size));
120 }
121 }
122
UpdateInformation(SctpTransportState state)123 void SctpTransport::UpdateInformation(SctpTransportState state) {
124 RTC_DCHECK_RUN_ON(owner_thread_);
125 bool must_send_update;
126 SctpTransportInformation info_copy(SctpTransportState::kNew);
127 {
128 rtc::CritScope scope(&lock_);
129 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 if (observer_ && must_send_update) {
140 info_copy = info_;
141 }
142 }
143 // We call the observer without holding the lock.
144 if (observer_ && must_send_update) {
145 observer_->OnStateChange(info_copy);
146 }
147 }
148
OnAssociationChangeCommunicationUp()149 void SctpTransport::OnAssociationChangeCommunicationUp() {
150 RTC_DCHECK_RUN_ON(owner_thread_);
151 {
152 rtc::CritScope scope(&lock_);
153 RTC_DCHECK(internal_sctp_transport_);
154 if (internal_sctp_transport_->max_outbound_streams() &&
155 internal_sctp_transport_->max_inbound_streams()) {
156 int max_channels =
157 std::min(*(internal_sctp_transport_->max_outbound_streams()),
158 *(internal_sctp_transport_->max_inbound_streams()));
159 // Record max channels.
160 info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(),
161 info_.MaxMessageSize(), max_channels);
162 }
163 }
164 UpdateInformation(SctpTransportState::kConnected);
165 }
166
OnDtlsStateChange(cricket::DtlsTransportInternal * transport,cricket::DtlsTransportState state)167 void SctpTransport::OnDtlsStateChange(cricket::DtlsTransportInternal* transport,
168 cricket::DtlsTransportState state) {
169 RTC_DCHECK_RUN_ON(owner_thread_);
170 RTC_CHECK(transport == dtls_transport_->internal());
171 if (state == cricket::DTLS_TRANSPORT_CLOSED ||
172 state == cricket::DTLS_TRANSPORT_FAILED) {
173 UpdateInformation(SctpTransportState::kClosed);
174 // TODO(http://bugs.webrtc.org/11090): Close all the data channels
175 }
176 }
177
178 } // namespace webrtc
179