blob: 532e91c67d7ea720f6172b101b3e7e4fb8b6d8b2 [file] [log] [blame]
Harald Alvestrandc85328f2019-02-28 07:51:00 +01001/*
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
Harald Alvestrand97716c02019-05-21 10:52:59 +020013#include <algorithm>
Harald Alvestrandc85328f2019-02-28 07:51:00 +010014#include <utility>
15
16namespace webrtc {
17
18SctpTransport::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());
Harald Alvestrand97716c02019-05-21 10:52:59 +020024 internal_sctp_transport_->SignalAssociationChangeCommunicationUp.connect(
25 this, &SctpTransport::OnAssociationChangeCommunicationUp);
Harald Alvestrandc85328f2019-02-28 07:51:00 +010026 // 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
35SctpTransport::~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
41SctpTransportInformation SctpTransport::Information() const {
42 rtc::CritScope scope(&lock_);
43 return info_;
44}
45
46void SctpTransport::RegisterObserver(SctpTransportObserverInterface* observer) {
47 RTC_DCHECK_RUN_ON(owner_thread_);
48 RTC_DCHECK(observer);
49 RTC_DCHECK(!observer_);
50 observer_ = observer;
51}
52
53void SctpTransport::UnregisterObserver() {
54 RTC_DCHECK_RUN_ON(owner_thread_);
55 observer_ = nullptr;
56}
57
58rtc::scoped_refptr<DtlsTransportInterface> SctpTransport::dtls_transport()
59 const {
60 RTC_DCHECK_RUN_ON(owner_thread_);
61 return dtls_transport_;
62}
63
64// Internal functions
65void 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
78void SctpTransport::SetDtlsTransport(
79 rtc::scoped_refptr<DtlsTransport> transport) {
80 RTC_DCHECK_RUN_ON(owner_thread_);
Harald Alvestrandd61f2a72019-05-08 20:20:59 +020081 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());
Harald Alvestrand408cb4b2019-11-16 12:09:08 +010089 transport->internal()->SignalDtlsState.connect(
90 this, &SctpTransport::OnDtlsStateChange);
Harald Alvestrandd61f2a72019-05-08 20:20:59 +020091 if (info_.state() == SctpTransportState::kNew) {
92 next_state = SctpTransportState::kConnecting;
93 }
94 } else {
95 internal_sctp_transport_->SetDtlsTransport(nullptr);
Harald Alvestrandc85328f2019-02-28 07:51:00 +010096 }
Harald Alvestrandc85328f2019-02-28 07:51:00 +010097 }
98 }
Harald Alvestrandd61f2a72019-05-08 20:20:59 +020099 UpdateInformation(next_state);
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100100}
101
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +0200102void 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
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100123void 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());
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +0200130 // TODO(https://bugs.webrtc.org/10358): Update max channels from internal
131 // SCTP transport when available.
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +0200132 if (internal_sctp_transport_) {
133 info_ = SctpTransportInformation(
Harald Alvestrand8d3d6cf2019-05-16 11:49:17 +0200134 state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
Harald Alvestrandfbb45bd2019-05-15 08:07:47 +0200135 } else {
136 info_ = SctpTransportInformation(
137 state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
138 }
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100139 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
Harald Alvestrand97716c02019-05-21 10:52:59 +0200149void 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 }
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100164 UpdateInformation(SctpTransportState::kConnected);
165}
166
Harald Alvestrand408cb4b2019-11-16 12:09:08 +0100167void 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
Harald Alvestrandc85328f2019-02-28 07:51:00 +0100178} // namespace webrtc