2019-12-02 09:56:02 +01:00
|
|
|
/*
|
|
|
|
|
* Copyright 2019 The WebRTC project authors. All Rights Reserved.
|
|
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
#include "pc/data_channel_controller.h"
|
|
|
|
|
|
|
|
|
|
#include <utility>
|
2019-12-02 09:56:02 +01:00
|
|
|
|
2023-03-14 09:23:51 +01:00
|
|
|
#include "absl/algorithm/container.h"
|
2021-01-29 14:45:08 +00:00
|
|
|
#include "api/peer_connection_interface.h"
|
|
|
|
|
#include "api/rtc_error.h"
|
2022-02-08 10:49:09 +00:00
|
|
|
#include "pc/peer_connection_internal.h"
|
2019-12-02 09:56:02 +01:00
|
|
|
#include "pc/sctp_utils.h"
|
2021-01-29 14:45:08 +00:00
|
|
|
#include "rtc_base/logging.h"
|
2019-12-02 09:56:02 +01:00
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
|
2023-03-02 15:42:06 +01:00
|
|
|
DataChannelController::~DataChannelController() {}
|
2022-05-11 09:35:36 +00:00
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
bool DataChannelController::HasDataChannels() const {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
2021-04-16 11:12:14 +00:00
|
|
|
return !sctp_data_channels_.empty();
|
2019-12-03 14:04:21 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-15 20:39:42 +00:00
|
|
|
bool DataChannelController::HasUsedDataChannels() const {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
|
|
|
return has_used_data_channels_;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-21 14:48:51 +01:00
|
|
|
RTCError DataChannelController::SendData(
|
|
|
|
|
StreamId sid,
|
|
|
|
|
const SendDataParams& params,
|
|
|
|
|
const rtc::CopyOnWriteBuffer& payload) {
|
2020-06-15 13:47:42 +02:00
|
|
|
if (data_channel_transport())
|
2023-03-21 14:48:51 +01:00
|
|
|
return DataChannelSendData(sid, params, payload);
|
2019-12-02 09:56:02 +01:00
|
|
|
RTC_LOG(LS_ERROR) << "SendData called before transport is ready";
|
2023-03-21 14:48:51 +01:00
|
|
|
return RTCError(RTCErrorType::INVALID_STATE);
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-21 11:35:24 +01:00
|
|
|
void DataChannelController::AddSctpDataStream(StreamId sid) {
|
2019-12-02 09:56:02 +01:00
|
|
|
if (data_channel_transport()) {
|
2022-09-08 18:38:10 +02:00
|
|
|
network_thread()->BlockingCall([this, sid] {
|
2019-12-02 09:56:02 +01:00
|
|
|
if (data_channel_transport()) {
|
2023-03-21 11:35:24 +01:00
|
|
|
data_channel_transport()->OpenChannel(sid.stream_id_int());
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-21 11:35:24 +01:00
|
|
|
void DataChannelController::RemoveSctpDataStream(StreamId sid) {
|
2019-12-02 09:56:02 +01:00
|
|
|
if (data_channel_transport()) {
|
2022-09-08 18:38:10 +02:00
|
|
|
network_thread()->BlockingCall([this, sid] {
|
2019-12-02 09:56:02 +01:00
|
|
|
if (data_channel_transport()) {
|
2023-03-21 11:35:24 +01:00
|
|
|
data_channel_transport()->CloseChannel(sid.stream_id_int());
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
bool DataChannelController::ReadyToSendData() const {
|
2019-12-02 09:56:02 +01:00
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
2021-04-16 11:12:14 +00:00
|
|
|
return (data_channel_transport() && data_channel_transport_ready_to_send_);
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
|
2023-03-02 10:51:16 +01:00
|
|
|
void DataChannelController::OnChannelStateChanged(
|
|
|
|
|
SctpDataChannel* channel,
|
|
|
|
|
DataChannelInterface::DataState state) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
|
|
|
if (state == DataChannelInterface::DataState::kClosed)
|
|
|
|
|
OnSctpDataChannelClosed(channel);
|
|
|
|
|
|
|
|
|
|
pc_->OnSctpDataChannelStateChanged(channel, state);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
void DataChannelController::OnDataReceived(
|
2019-12-02 09:56:02 +01:00
|
|
|
int channel_id,
|
|
|
|
|
DataMessageType type,
|
|
|
|
|
const rtc::CopyOnWriteBuffer& buffer) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(network_thread());
|
2023-03-04 16:47:53 +01:00
|
|
|
|
2023-03-15 12:36:20 +01:00
|
|
|
if (HandleOpenMessage_n(channel_id, type, buffer))
|
2023-03-04 16:47:53 +01:00
|
|
|
return;
|
|
|
|
|
|
2021-03-23 09:23:10 +01:00
|
|
|
signaling_thread()->PostTask(
|
2023-03-15 12:36:20 +01:00
|
|
|
SafeTask(signaling_safety_.flag(), [this, channel_id, type, buffer] {
|
2023-03-06 12:51:39 +01:00
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
|
|
|
// TODO(bugs.webrtc.org/11547): The data being received should be
|
2023-03-14 13:21:06 +01:00
|
|
|
// delivered on the network thread.
|
2023-03-20 10:26:19 +01:00
|
|
|
auto it = FindChannel(StreamId(channel_id));
|
|
|
|
|
if (it != sctp_data_channels_.end())
|
|
|
|
|
(*it)->OnDataReceived(type, buffer);
|
2023-03-06 12:51:39 +01:00
|
|
|
}));
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
void DataChannelController::OnChannelClosing(int channel_id) {
|
2019-12-02 09:56:02 +01:00
|
|
|
RTC_DCHECK_RUN_ON(network_thread());
|
2023-03-06 12:51:39 +01:00
|
|
|
signaling_thread()->PostTask(
|
|
|
|
|
SafeTask(signaling_safety_.flag(), [this, channel_id] {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
2023-03-14 13:21:06 +01:00
|
|
|
// TODO(bugs.webrtc.org/11547): Should run on the network thread.
|
2023-03-20 10:26:19 +01:00
|
|
|
auto it = FindChannel(StreamId(channel_id));
|
|
|
|
|
if (it != sctp_data_channels_.end())
|
|
|
|
|
(*it)->OnClosingProcedureStartedRemotely();
|
2023-03-06 12:51:39 +01:00
|
|
|
}));
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
void DataChannelController::OnChannelClosed(int channel_id) {
|
2019-12-02 09:56:02 +01:00
|
|
|
RTC_DCHECK_RUN_ON(network_thread());
|
2023-03-06 12:51:39 +01:00
|
|
|
signaling_thread()->PostTask(
|
|
|
|
|
SafeTask(signaling_safety_.flag(), [this, channel_id] {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
2023-03-20 10:26:19 +01:00
|
|
|
auto it = FindChannel(StreamId(channel_id));
|
2023-03-14 09:23:51 +01:00
|
|
|
// Remove the channel from our list, close it and free up resources.
|
|
|
|
|
if (it != sctp_data_channels_.end()) {
|
|
|
|
|
rtc::scoped_refptr<SctpDataChannel> channel = std::move(*it);
|
|
|
|
|
// Note: this causes OnSctpDataChannelClosed() to not do anything
|
|
|
|
|
// when called from within `OnClosingProcedureComplete`.
|
|
|
|
|
sctp_data_channels_.erase(it);
|
|
|
|
|
sid_allocator_.ReleaseSid(channel->sid());
|
|
|
|
|
|
|
|
|
|
channel->OnClosingProcedureComplete();
|
|
|
|
|
}
|
2023-03-06 12:51:39 +01:00
|
|
|
}));
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
void DataChannelController::OnReadyToSend() {
|
2019-12-02 09:56:02 +01:00
|
|
|
RTC_DCHECK_RUN_ON(network_thread());
|
2023-03-06 12:51:39 +01:00
|
|
|
signaling_thread()->PostTask(SafeTask(signaling_safety_.flag(), [this] {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
|
|
|
data_channel_transport_ready_to_send_ = true;
|
2023-03-16 22:17:38 +01:00
|
|
|
auto copy = sctp_data_channels_;
|
|
|
|
|
for (const auto& channel : copy)
|
2023-03-20 14:43:09 +01:00
|
|
|
channel->OnTransportReady();
|
2023-03-06 12:51:39 +01:00
|
|
|
}));
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
|
2021-06-29 14:58:23 +02:00
|
|
|
void DataChannelController::OnTransportClosed(RTCError error) {
|
2019-12-16 10:37:04 +01:00
|
|
|
RTC_DCHECK_RUN_ON(network_thread());
|
2023-03-06 12:51:39 +01:00
|
|
|
signaling_thread()->PostTask(
|
|
|
|
|
SafeTask(signaling_safety_.flag(), [this, error] {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
|
|
|
OnTransportChannelClosed(error);
|
|
|
|
|
}));
|
2019-12-16 10:37:04 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
void DataChannelController::SetupDataChannelTransport_n() {
|
2019-12-02 09:56:02 +01:00
|
|
|
RTC_DCHECK_RUN_ON(network_thread());
|
2020-06-16 16:54:10 +02:00
|
|
|
|
|
|
|
|
// There's a new data channel transport. This needs to be signaled to the
|
2021-07-30 22:30:23 +02:00
|
|
|
// `sctp_data_channels_` so that they can reopen and reconnect. This is
|
2020-06-16 16:54:10 +02:00
|
|
|
// necessary when bundling is applied.
|
|
|
|
|
NotifyDataChannelsOfTransportCreated();
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
void DataChannelController::TeardownDataChannelTransport_n() {
|
2019-12-02 09:56:02 +01:00
|
|
|
RTC_DCHECK_RUN_ON(network_thread());
|
|
|
|
|
if (data_channel_transport()) {
|
|
|
|
|
data_channel_transport()->SetDataSink(nullptr);
|
|
|
|
|
}
|
|
|
|
|
set_data_channel_transport(nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
void DataChannelController::OnTransportChanged(
|
2019-12-02 09:56:02 +01:00
|
|
|
DataChannelTransportInterface* new_data_channel_transport) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(network_thread());
|
|
|
|
|
if (data_channel_transport() &&
|
|
|
|
|
data_channel_transport() != new_data_channel_transport) {
|
2021-07-30 22:30:23 +02:00
|
|
|
// Changed which data channel transport is used for `sctp_mid_` (eg. now
|
2019-12-02 09:56:02 +01:00
|
|
|
// it's bundled).
|
|
|
|
|
data_channel_transport()->SetDataSink(nullptr);
|
|
|
|
|
set_data_channel_transport(new_data_channel_transport);
|
|
|
|
|
if (new_data_channel_transport) {
|
|
|
|
|
new_data_channel_transport->SetDataSink(this);
|
|
|
|
|
|
|
|
|
|
// There's a new data channel transport. This needs to be signaled to the
|
2021-07-30 22:30:23 +02:00
|
|
|
// `sctp_data_channels_` so that they can reopen and reconnect. This is
|
2019-12-02 09:56:02 +01:00
|
|
|
// necessary when bundling is applied.
|
2020-06-16 16:54:10 +02:00
|
|
|
NotifyDataChannelsOfTransportCreated();
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-09 15:32:34 -07:00
|
|
|
std::vector<DataChannelStats> DataChannelController::GetDataChannelStats()
|
2020-06-16 16:54:10 +02:00
|
|
|
const {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
2020-07-09 15:32:34 -07:00
|
|
|
std::vector<DataChannelStats> stats;
|
2020-06-16 16:54:10 +02:00
|
|
|
stats.reserve(sctp_data_channels_.size());
|
|
|
|
|
for (const auto& channel : sctp_data_channels_)
|
|
|
|
|
stats.push_back(channel->GetStats());
|
|
|
|
|
return stats;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-04 16:47:53 +01:00
|
|
|
bool DataChannelController::HandleOpenMessage_n(
|
2023-03-15 12:36:20 +01:00
|
|
|
int channel_id,
|
|
|
|
|
DataMessageType type,
|
2019-12-02 09:56:02 +01:00
|
|
|
const rtc::CopyOnWriteBuffer& buffer) {
|
2023-03-15 12:36:20 +01:00
|
|
|
if (type != DataMessageType::kControl || !IsOpenMessage(buffer))
|
2023-03-04 16:47:53 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Received OPEN message; parse and signal that a new data channel should
|
|
|
|
|
// be created.
|
|
|
|
|
std::string label;
|
|
|
|
|
InternalDataChannelInit config;
|
2023-03-15 12:36:20 +01:00
|
|
|
config.id = channel_id;
|
2023-03-04 16:47:53 +01:00
|
|
|
if (!ParseDataChannelOpenMessage(buffer, &label, &config)) {
|
|
|
|
|
RTC_LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
|
2023-03-15 12:36:20 +01:00
|
|
|
<< channel_id;
|
2023-03-04 16:47:53 +01:00
|
|
|
} else {
|
2019-12-02 09:56:02 +01:00
|
|
|
config.open_handshake_role = InternalDataChannelInit::kAcker;
|
2023-03-06 12:51:39 +01:00
|
|
|
signaling_thread()->PostTask(
|
|
|
|
|
SafeTask(signaling_safety_.flag(),
|
|
|
|
|
[this, label = std::move(label), config = std::move(config)] {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
|
|
|
OnDataChannelOpenMessage(label, config);
|
|
|
|
|
}));
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
2023-03-04 16:47:53 +01:00
|
|
|
return true;
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
void DataChannelController::OnDataChannelOpenMessage(
|
2019-12-02 09:56:02 +01:00
|
|
|
const std::string& label,
|
|
|
|
|
const InternalDataChannelInit& config) {
|
2020-07-09 15:32:34 -07:00
|
|
|
rtc::scoped_refptr<DataChannelInterface> channel(
|
|
|
|
|
InternalCreateDataChannelWithProxy(label, &config));
|
2019-12-02 09:56:02 +01:00
|
|
|
if (!channel.get()) {
|
|
|
|
|
RTC_LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message.";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-09 15:32:34 -07:00
|
|
|
pc_->Observer()->OnDataChannel(std::move(channel));
|
2019-12-03 14:04:21 +01:00
|
|
|
pc_->NoteDataAddedEvent();
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
|
2020-07-09 15:32:34 -07:00
|
|
|
rtc::scoped_refptr<DataChannelInterface>
|
|
|
|
|
DataChannelController::InternalCreateDataChannelWithProxy(
|
2019-12-02 09:56:02 +01:00
|
|
|
const std::string& label,
|
|
|
|
|
const InternalDataChannelInit* config) {
|
2019-12-03 14:04:21 +01:00
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
2019-12-02 09:56:02 +01:00
|
|
|
if (pc_->IsClosed()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2021-04-19 15:29:50 +02:00
|
|
|
|
|
|
|
|
rtc::scoped_refptr<SctpDataChannel> channel =
|
|
|
|
|
InternalCreateSctpDataChannel(label, config);
|
|
|
|
|
if (channel) {
|
|
|
|
|
return SctpDataChannel::CreateProxy(channel);
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
|
2020-07-09 15:32:34 -07:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rtc::scoped_refptr<SctpDataChannel>
|
|
|
|
|
DataChannelController::InternalCreateSctpDataChannel(
|
|
|
|
|
const std::string& label,
|
|
|
|
|
const InternalDataChannelInit* config) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
2023-03-21 16:28:52 +01:00
|
|
|
if (config && !config->IsValid()) {
|
|
|
|
|
RTC_LOG(LS_ERROR) << "Failed to initialize the SCTP data channel due to "
|
|
|
|
|
"invalid DataChannelInit.";
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-09 15:32:34 -07:00
|
|
|
InternalDataChannelInit new_config =
|
|
|
|
|
config ? (*config) : InternalDataChannelInit();
|
2023-03-12 16:59:25 +01:00
|
|
|
StreamId sid(new_config.id);
|
|
|
|
|
if (!sid.HasValue()) {
|
2020-07-09 15:32:34 -07:00
|
|
|
rtc::SSLRole role;
|
2023-03-12 16:59:25 +01:00
|
|
|
// TODO(bugs.webrtc.org/11547): `GetSctpSslRole` likely involves a hop to
|
|
|
|
|
// the network thread. (unless there's no transport). Change this so that
|
|
|
|
|
// the role is checked on the network thread and any network thread related
|
|
|
|
|
// initialization is done at the same time (to avoid additional hops).
|
2023-03-22 08:25:38 +01:00
|
|
|
// Use `GetSctpSslRole_n` on the network thread.
|
2023-03-21 18:45:24 +01:00
|
|
|
if (pc_->GetSctpSslRole(&role)) {
|
|
|
|
|
sid = sid_allocator_.AllocateSid(role);
|
|
|
|
|
if (!sid.HasValue())
|
|
|
|
|
return nullptr;
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
2023-03-12 16:59:25 +01:00
|
|
|
// Note that when we get here, the ID may still be invalid.
|
|
|
|
|
} else if (!sid_allocator_.ReserveSid(sid)) {
|
2020-07-09 15:32:34 -07:00
|
|
|
RTC_LOG(LS_ERROR) << "Failed to create a SCTP data channel "
|
|
|
|
|
"because the id is already in use or out of range.";
|
|
|
|
|
return nullptr;
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
2023-03-12 16:59:25 +01:00
|
|
|
// In case `sid` has changed. Update `new_config` accordingly.
|
|
|
|
|
new_config.id = sid.stream_id_int();
|
2023-03-20 14:43:09 +01:00
|
|
|
// TODO(bugs.webrtc.org/11547): The `data_channel_transport_` pointer belongs
|
|
|
|
|
// to the network thread but there are a few places where we check this
|
|
|
|
|
// pointer from the signaling thread. Instead of this approach, we should have
|
|
|
|
|
// a separate channel initialization step that runs on the network thread
|
|
|
|
|
// where we inform the channel of information about whether there's a
|
|
|
|
|
// transport or not, what the role is, and supply an id if any. Subsequently
|
|
|
|
|
// all that state in the channel code, is needed for callbacks from the
|
|
|
|
|
// transport which is already initiated from the network thread. Then we can
|
|
|
|
|
// Remove the trampoline code (see e.g. PostTask() calls in this file) that
|
|
|
|
|
// travels between the signaling and network threads.
|
|
|
|
|
rtc::scoped_refptr<SctpDataChannel> channel(SctpDataChannel::Create(
|
|
|
|
|
weak_factory_.GetWeakPtr(), label, data_channel_transport() != nullptr,
|
|
|
|
|
new_config, signaling_thread(), network_thread()));
|
2023-03-21 16:28:52 +01:00
|
|
|
RTC_DCHECK(channel);
|
|
|
|
|
|
|
|
|
|
if (ReadyToSendData()) {
|
|
|
|
|
// Checks if the transport is ready to send because the initial channel
|
|
|
|
|
// ready signal may have been sent before the DataChannel creation.
|
|
|
|
|
// This has to be done async because the upper layer objects (e.g.
|
|
|
|
|
// Chrome glue and WebKit) are not wired up properly until after this
|
|
|
|
|
// function returns.
|
|
|
|
|
signaling_thread()->PostTask(
|
|
|
|
|
SafeTask(signaling_safety_.flag(), [channel = channel] {
|
|
|
|
|
if (channel->state() != DataChannelInterface::DataState::kClosed)
|
|
|
|
|
channel->OnTransportReady();
|
|
|
|
|
}));
|
2020-07-09 15:32:34 -07:00
|
|
|
}
|
2023-03-21 16:28:52 +01:00
|
|
|
|
2020-07-09 15:32:34 -07:00
|
|
|
sctp_data_channels_.push_back(channel);
|
2023-03-15 20:39:42 +00:00
|
|
|
has_used_data_channels_ = true;
|
2019-12-02 09:56:02 +01:00
|
|
|
return channel;
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
void DataChannelController::AllocateSctpSids(rtc::SSLRole role) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
2020-07-09 15:32:34 -07:00
|
|
|
std::vector<rtc::scoped_refptr<SctpDataChannel>> channels_to_close;
|
2019-12-03 14:04:21 +01:00
|
|
|
for (const auto& channel : sctp_data_channels_) {
|
2023-03-12 16:59:25 +01:00
|
|
|
if (!channel->sid().HasValue()) {
|
2023-03-21 18:45:24 +01:00
|
|
|
StreamId sid = sid_allocator_.AllocateSid(role);
|
|
|
|
|
if (!sid.HasValue()) {
|
2019-12-02 09:56:02 +01:00
|
|
|
channels_to_close.push_back(channel);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-03-12 16:59:25 +01:00
|
|
|
// TODO(bugs.webrtc.org/11547): This hides a blocking call to the network
|
|
|
|
|
// thread via AddSctpDataStream. Maybe it's better to move the whole loop
|
|
|
|
|
// to the network thread? Maybe even `sctp_data_channels_`?
|
2019-12-02 09:56:02 +01:00
|
|
|
channel->SetSctpSid(sid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Since closing modifies the list of channels, we have to do the actual
|
|
|
|
|
// closing outside the loop.
|
|
|
|
|
for (const auto& channel : channels_to_close) {
|
2019-12-08 05:55:43 +01:00
|
|
|
channel->CloseAbruptlyWithDataChannelFailure("Failed to allocate SCTP SID");
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-09 15:32:34 -07:00
|
|
|
void DataChannelController::OnSctpDataChannelClosed(SctpDataChannel* channel) {
|
2019-12-03 14:04:21 +01:00
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
|
|
|
for (auto it = sctp_data_channels_.begin(); it != sctp_data_channels_.end();
|
|
|
|
|
++it) {
|
2019-12-02 09:56:02 +01:00
|
|
|
if (it->get() == channel) {
|
2023-03-12 16:59:25 +01:00
|
|
|
if (channel->sid().HasValue()) {
|
2019-12-02 09:56:02 +01:00
|
|
|
// After the closing procedure is done, it's safe to use this ID for
|
|
|
|
|
// another data channel.
|
2023-03-12 16:59:25 +01:00
|
|
|
sid_allocator_.ReleaseSid(channel->sid());
|
2019-12-02 09:56:02 +01:00
|
|
|
}
|
2023-03-09 23:52:43 +01:00
|
|
|
|
2019-12-02 09:56:02 +01:00
|
|
|
// Since this method is triggered by a signal from the DataChannel,
|
|
|
|
|
// we can't free it directly here; we need to free it asynchronously.
|
2023-03-09 23:52:43 +01:00
|
|
|
rtc::scoped_refptr<SctpDataChannel> release = std::move(*it);
|
2019-12-03 14:04:21 +01:00
|
|
|
sctp_data_channels_.erase(it);
|
2023-03-09 23:52:43 +01:00
|
|
|
signaling_thread()->PostTask(SafeTask(signaling_safety_.flag(),
|
|
|
|
|
[release = std::move(release)] {}));
|
2019-12-02 09:56:02 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-29 14:58:23 +02:00
|
|
|
void DataChannelController::OnTransportChannelClosed(RTCError error) {
|
2019-12-03 14:04:21 +01:00
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
2021-04-16 11:12:14 +00:00
|
|
|
// Use a temporary copy of the SCTP DataChannel list because the
|
2019-12-03 14:04:21 +01:00
|
|
|
// DataChannel may callback to us and try to modify the list.
|
2023-03-21 16:28:52 +01:00
|
|
|
// TODO(tommi): `OnTransportChannelClosed` is called from
|
|
|
|
|
// `SdpOfferAnswerHandler::DestroyDataChannelTransport` just before
|
|
|
|
|
// `TeardownDataChannelTransport_n` is called (but on the network thread) from
|
|
|
|
|
// the same function. Once `sctp_data_channels_` moves to the network thread,
|
|
|
|
|
// we can get rid of this function (OnTransportChannelClosed) and run this
|
|
|
|
|
// loop from within the TeardownDataChannelTransport_n callback.
|
2020-07-09 15:32:34 -07:00
|
|
|
std::vector<rtc::scoped_refptr<SctpDataChannel>> temp_sctp_dcs;
|
2019-12-03 14:04:21 +01:00
|
|
|
temp_sctp_dcs.swap(sctp_data_channels_);
|
|
|
|
|
for (const auto& channel : temp_sctp_dcs) {
|
2021-06-29 14:58:23 +02:00
|
|
|
channel->OnTransportChannelClosed(error);
|
2019-12-03 14:04:21 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-15 13:47:42 +02:00
|
|
|
DataChannelTransportInterface* DataChannelController::data_channel_transport()
|
|
|
|
|
const {
|
|
|
|
|
// TODO(bugs.webrtc.org/11547): Only allow this accessor to be called on the
|
|
|
|
|
// network thread.
|
|
|
|
|
// RTC_DCHECK_RUN_ON(network_thread());
|
|
|
|
|
return data_channel_transport_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DataChannelController::set_data_channel_transport(
|
|
|
|
|
DataChannelTransportInterface* transport) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(network_thread());
|
|
|
|
|
data_channel_transport_ = transport;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-21 14:48:51 +01:00
|
|
|
RTCError DataChannelController::DataChannelSendData(
|
2023-03-21 11:35:24 +01:00
|
|
|
StreamId sid,
|
2021-05-10 11:29:56 +02:00
|
|
|
const SendDataParams& params,
|
2023-03-21 14:48:51 +01:00
|
|
|
const rtc::CopyOnWriteBuffer& payload) {
|
2020-06-15 13:47:42 +02:00
|
|
|
// TODO(bugs.webrtc.org/11547): Expect method to be called on the network
|
2023-03-02 10:51:16 +01:00
|
|
|
// thread instead. Remove the BlockingCall() below and move associated state
|
|
|
|
|
// to the network thread.
|
2020-06-15 13:47:42 +02:00
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
|
|
|
RTC_DCHECK(data_channel_transport());
|
|
|
|
|
|
2023-03-21 14:48:51 +01:00
|
|
|
return network_thread()->BlockingCall([this, sid, params, payload] {
|
2023-03-21 11:35:24 +01:00
|
|
|
return data_channel_transport()->SendData(sid.stream_id_int(), params,
|
|
|
|
|
payload);
|
2022-09-08 18:38:10 +02:00
|
|
|
});
|
2020-06-15 13:47:42 +02:00
|
|
|
}
|
|
|
|
|
|
2020-06-16 16:54:10 +02:00
|
|
|
void DataChannelController::NotifyDataChannelsOfTransportCreated() {
|
|
|
|
|
RTC_DCHECK_RUN_ON(network_thread());
|
2023-03-20 14:43:09 +01:00
|
|
|
RTC_DCHECK(data_channel_transport());
|
2023-03-06 12:51:39 +01:00
|
|
|
signaling_thread()->PostTask(SafeTask(signaling_safety_.flag(), [this] {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
2023-03-16 22:17:38 +01:00
|
|
|
auto copy = sctp_data_channels_;
|
|
|
|
|
for (const auto& channel : copy) {
|
2023-03-06 12:51:39 +01:00
|
|
|
channel->OnTransportChannelCreated();
|
2022-07-07 10:08:49 +02:00
|
|
|
}
|
2023-03-06 12:51:39 +01:00
|
|
|
}));
|
2020-06-16 16:54:10 +02:00
|
|
|
}
|
|
|
|
|
|
2023-03-20 10:26:19 +01:00
|
|
|
std::vector<rtc::scoped_refptr<SctpDataChannel>>::iterator
|
|
|
|
|
DataChannelController::FindChannel(StreamId stream_id) {
|
|
|
|
|
RTC_DCHECK_RUN_ON(signaling_thread());
|
|
|
|
|
return absl::c_find_if(sctp_data_channels_,
|
|
|
|
|
[&](const auto& c) { return c->sid() == stream_id; });
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-03 14:04:21 +01:00
|
|
|
rtc::Thread* DataChannelController::network_thread() const {
|
|
|
|
|
return pc_->network_thread();
|
|
|
|
|
}
|
|
|
|
|
rtc::Thread* DataChannelController::signaling_thread() const {
|
|
|
|
|
return pc_->signaling_thread();
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-02 09:56:02 +01:00
|
|
|
} // namespace webrtc
|