blob: 7f55e39d9eddfdf0e52fb5b1556fcd34fc3430be [file] [log] [blame]
Harald Alvestrandc85328f2019-02-28 06:51:001/*
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 08:52:5913#include <algorithm>
Harald Alvestrandc85328f2019-02-28 06:51:0014#include <utility>
15
Harald Alvestrand5761e7b2021-01-29 14:45:0816#include "absl/types/optional.h"
Mirko Bonadei9f6808b2021-05-21 18:46:0917#include "api/dtls_transport_interface.h"
Artem Titovd15a5752021-02-10 13:31:2418#include "api/sequence_checker.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0819#include "rtc_base/checks.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0820#include "rtc_base/logging.h"
Harald Alvestrand5761e7b2021-01-29 14:45:0821
Harald Alvestrandc85328f2019-02-28 06:51:0022namespace webrtc {
23
24SctpTransport::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());
Fredrik Solenberg5cb3a902022-08-22 09:34:2930 internal_sctp_transport_->SetOnConnectedCallback(
31 [this]() { OnAssociationChangeCommunicationUp(); });
Harald Alvestrandc85328f2019-02-28 06:51:0032
33 if (dtls_transport_) {
34 UpdateInformation(SctpTransportState::kConnecting);
35 } else {
36 UpdateInformation(SctpTransportState::kNew);
37 }
38}
39
40SctpTransport::~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
46SctpTransportInformation SctpTransport::Information() const {
Tomas Gunnarsson92eebef2021-02-10 12:05:4447 // 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()) {
Danil Chapovalov9e09a1f2022-09-08 16:38:1052 return owner_thread_->BlockingCall([this] { return Information(); });
Tomas Gunnarsson92eebef2021-02-10 12:05:4453 }
54 RTC_DCHECK_RUN_ON(owner_thread_);
Harald Alvestrandc85328f2019-02-28 06:51:0055 return info_;
56}
57
58void SctpTransport::RegisterObserver(SctpTransportObserverInterface* observer) {
59 RTC_DCHECK_RUN_ON(owner_thread_);
60 RTC_DCHECK(observer);
61 RTC_DCHECK(!observer_);
62 observer_ = observer;
63}
64
65void SctpTransport::UnregisterObserver() {
66 RTC_DCHECK_RUN_ON(owner_thread_);
67 observer_ = nullptr;
68}
69
Fredrik Solenberg5cb3a902022-08-22 09:34:2970RTCError 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
77RTCError SctpTransport::SendData(int channel_id,
78 const SendDataParams& params,
79 const rtc::CopyOnWriteBuffer& buffer) {
80 RTC_DCHECK_RUN_ON(owner_thread_);
Tommi1fabbac2023-03-21 13:48:5181 return internal_sctp_transport_->SendData(channel_id, params, buffer);
Fredrik Solenberg5cb3a902022-08-22 09:34:2982}
83
84RTCError SctpTransport::CloseChannel(int channel_id) {
85 RTC_DCHECK_RUN_ON(owner_thread_);
86 RTC_DCHECK(internal_sctp_transport_);
87 internal_sctp_transport_->ResetStream(channel_id);
88 return RTCError::OK();
89}
90
91void SctpTransport::SetDataSink(DataChannelSink* sink) {
92 RTC_DCHECK_RUN_ON(owner_thread_);
93 RTC_DCHECK(internal_sctp_transport_);
94 internal_sctp_transport_->SetDataChannelSink(sink);
95}
96
97bool SctpTransport::IsReadyToSend() const {
98 RTC_DCHECK_RUN_ON(owner_thread_);
99 RTC_DCHECK(internal_sctp_transport_);
100 return internal_sctp_transport_->ReadyToSendData();
101}
102
Harald Alvestrandc85328f2019-02-28 06:51:00103rtc::scoped_refptr<DtlsTransportInterface> SctpTransport::dtls_transport()
104 const {
105 RTC_DCHECK_RUN_ON(owner_thread_);
106 return dtls_transport_;
107}
108
109// Internal functions
110void SctpTransport::Clear() {
111 RTC_DCHECK_RUN_ON(owner_thread_);
112 RTC_DCHECK(internal());
Tomas Gunnarsson92eebef2021-02-10 12:05:44113 // Note that we delete internal_sctp_transport_, but
114 // only drop the reference to dtls_transport_.
115 dtls_transport_ = nullptr;
116 internal_sctp_transport_ = nullptr;
Harald Alvestrandc85328f2019-02-28 06:51:00117 UpdateInformation(SctpTransportState::kClosed);
118}
119
120void SctpTransport::SetDtlsTransport(
121 rtc::scoped_refptr<DtlsTransport> transport) {
122 RTC_DCHECK_RUN_ON(owner_thread_);
Tomas Gunnarsson92eebef2021-02-10 12:05:44123 SctpTransportState next_state = info_.state();
124 dtls_transport_ = transport;
125 if (internal_sctp_transport_) {
126 if (transport) {
127 internal_sctp_transport_->SetDtlsTransport(transport->internal());
Lahiru Ginnaliya Gamathige60c0b442021-02-16 15:29:08128
Mirko Bonadei9f6808b2021-05-21 18:46:09129 transport->internal()->SubscribeDtlsTransportState(
Lahiru Ginnaliya Gamathige60c0b442021-02-16 15:29:08130 [this](cricket::DtlsTransportInternal* transport,
Mirko Bonadei9f6808b2021-05-21 18:46:09131 DtlsTransportState state) {
Lahiru Ginnaliya Gamathige60c0b442021-02-16 15:29:08132 OnDtlsStateChange(transport, state);
133 });
Tomas Gunnarsson92eebef2021-02-10 12:05:44134 if (info_.state() == SctpTransportState::kNew) {
135 next_state = SctpTransportState::kConnecting;
Harald Alvestrandc85328f2019-02-28 06:51:00136 }
Tomas Gunnarsson92eebef2021-02-10 12:05:44137 } else {
138 internal_sctp_transport_->SetDtlsTransport(nullptr);
Harald Alvestrandc85328f2019-02-28 06:51:00139 }
140 }
Tomas Gunnarsson92eebef2021-02-10 12:05:44141
Harald Alvestrandd61f2a72019-05-08 18:20:59142 UpdateInformation(next_state);
Harald Alvestrandc85328f2019-02-28 06:51:00143}
144
Harald Alvestrand8d3d6cf2019-05-16 09:49:17145void SctpTransport::Start(int local_port,
146 int remote_port,
147 int max_message_size) {
Tomas Gunnarsson92eebef2021-02-10 12:05:44148 RTC_DCHECK_RUN_ON(owner_thread_);
149 info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(),
150 max_message_size, info_.MaxChannels());
151
152 if (!internal()->Start(local_port, remote_port, max_message_size)) {
153 RTC_LOG(LS_ERROR) << "Failed to push down SCTP parameters, closing.";
154 UpdateInformation(SctpTransportState::kClosed);
Harald Alvestrand8d3d6cf2019-05-16 09:49:17155 }
156}
157
Harald Alvestrandc85328f2019-02-28 06:51:00158void SctpTransport::UpdateInformation(SctpTransportState state) {
159 RTC_DCHECK_RUN_ON(owner_thread_);
Tomas Gunnarsson92eebef2021-02-10 12:05:44160 bool must_send_update = (state != info_.state());
161 // TODO(https://bugs.webrtc.org/10358): Update max channels from internal
162 // SCTP transport when available.
163 if (internal_sctp_transport_) {
164 info_ = SctpTransportInformation(
165 state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
166 } else {
167 info_ = SctpTransportInformation(
168 state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
Harald Alvestrandc85328f2019-02-28 06:51:00169 }
Tomas Gunnarsson92eebef2021-02-10 12:05:44170
Harald Alvestrandc85328f2019-02-28 06:51:00171 if (observer_ && must_send_update) {
Tomas Gunnarsson92eebef2021-02-10 12:05:44172 observer_->OnStateChange(info_);
Harald Alvestrandc85328f2019-02-28 06:51:00173 }
174}
175
Harald Alvestrand97716c02019-05-21 08:52:59176void SctpTransport::OnAssociationChangeCommunicationUp() {
177 RTC_DCHECK_RUN_ON(owner_thread_);
Tomas Gunnarsson92eebef2021-02-10 12:05:44178 RTC_DCHECK(internal_sctp_transport_);
179 if (internal_sctp_transport_->max_outbound_streams() &&
180 internal_sctp_transport_->max_inbound_streams()) {
181 int max_channels =
182 std::min(*(internal_sctp_transport_->max_outbound_streams()),
183 *(internal_sctp_transport_->max_inbound_streams()));
184 // Record max channels.
185 info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(),
186 info_.MaxMessageSize(), max_channels);
Harald Alvestrand97716c02019-05-21 08:52:59187 }
Tomas Gunnarsson92eebef2021-02-10 12:05:44188
Harald Alvestrandc85328f2019-02-28 06:51:00189 UpdateInformation(SctpTransportState::kConnected);
190}
191
Harald Alvestrand408cb4b2019-11-16 11:09:08192void SctpTransport::OnDtlsStateChange(cricket::DtlsTransportInternal* transport,
Mirko Bonadei9f6808b2021-05-21 18:46:09193 DtlsTransportState state) {
Harald Alvestrand408cb4b2019-11-16 11:09:08194 RTC_DCHECK_RUN_ON(owner_thread_);
195 RTC_CHECK(transport == dtls_transport_->internal());
Mirko Bonadei9f6808b2021-05-21 18:46:09196 if (state == DtlsTransportState::kClosed ||
197 state == DtlsTransportState::kFailed) {
Harald Alvestrand408cb4b2019-11-16 11:09:08198 UpdateInformation(SctpTransportState::kClosed);
199 // TODO(http://bugs.webrtc.org/11090): Close all the data channels
200 }
201}
202
Harald Alvestrandc85328f2019-02-28 06:51:00203} // namespace webrtc