/* * 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.
*/
// Stash away the internal id here in case `OnSctpDataChannelClosed` ends up // releasing the last reference to the channel. constint channel_id = channel->internal_id();
if (state == DataChannelInterface::DataState::kClosed)
OnSctpDataChannelClosed(channel);
void DataChannelController::OnReadyToSend() {
RTC_DCHECK_RUN_ON(network_thread()); auto copy = sctp_data_channels_n_; for (constauto& channel : copy) { if (channel->sid_n().has_value()) {
channel->OnTransportReady();
} else { // This happens for role==SSL_SERVER channels when we get notified by // the transport *before* the SDP code calls `AllocateSctpSids` to // trigger assignment of sids. In this case OnTransportReady() will be // called from within `AllocateSctpSids` below.
RTC_LOG(LS_INFO) << "OnReadyToSend: Still waiting for an id for channel.";
}
}
}
// This loop will close all data channels and trigger a callback to // `OnSctpDataChannelClosed`. We'll empty `sctp_data_channels_n_`, first // and `OnSctpDataChannelClosed` will become a noop but we'll release the // StreamId here.
std::vector<rtc::scoped_refptr<SctpDataChannel>> temp_sctp_dcs;
temp_sctp_dcs.swap(sctp_data_channels_n_); for (constauto& channel : temp_sctp_dcs) {
channel->OnTransportChannelClosed(error); if (channel->sid_n().has_value()) {
sid_allocator_.ReleaseSid(*channel->sid_n());
}
}
}
void DataChannelController::OnBufferedAmountLow(int channel_id) {
RTC_DCHECK_RUN_ON(network_thread()); auto it = absl::c_find_if(sctp_data_channels_n_, [&](constauto& c) { return c->sid_n().has_value() && c->sid_n()->stream_id_int() == channel_id;
});
if (it != sctp_data_channels_n_.end())
(*it)->OnBufferedAmountLow();
}
void DataChannelController::OnTransportChanged(
DataChannelTransportInterface* new_data_channel_transport) {
RTC_DCHECK_RUN_ON(network_thread()); if (data_channel_transport_ &&
data_channel_transport_ != new_data_channel_transport) { // Changed which data channel transport is used for `sctp_mid_` (eg. now // it's bundled).
set_data_channel_transport(new_data_channel_transport);
}
}
bool DataChannelController::HandleOpenMessage_n( int channel_id,
DataMessageType type, const rtc::CopyOnWriteBuffer& buffer) { if (type != DataMessageType::kControl || !IsOpenMessage(buffer)) returnfalse;
// Received OPEN message; parse and signal that a new data channel should // be created.
std::string label;
InternalDataChannelInit config;
config.id = channel_id; if (!ParseDataChannelOpenMessage(buffer, &label, &config)) {
RTC_LOG(LS_WARNING) << "Failed to parse the OPEN message for sid "
<< channel_id;
} else {
config.open_handshake_role = InternalDataChannelInit::kAcker; auto channel_or_error = CreateDataChannel(label, config); if (channel_or_error.ok()) {
signaling_thread()->PostTask(SafeTask(
signaling_safety_.flag(),
[this, channel = channel_or_error.MoveValue(),
ready_to_send = data_channel_transport_->IsReadyToSend()] {
RTC_DCHECK_RUN_ON(signaling_thread());
OnDataChannelOpenMessage(std::move(channel), ready_to_send);
}));
} else {
RTC_LOG(LS_ERROR) << "Failed to create DataChannel from the OPEN message."
<< ToString(channel_or_error.error().type());
}
} returntrue;
}
// Attempt to allocate an ID based on the negotiated role.
std::optional<rtc::SSLRole> role = pc_->GetSctpSslRole_n(); if (!role)
role = fallback_ssl_role; if (role) {
sid = sid_allocator_.AllocateSid(*role); if (!sid.has_value()) return RTCError(RTCErrorType::RESOURCE_EXHAUSTED);
} // When we get here, we may still not have an ID, but that's a supported case // whereby an id will be assigned later.
RTC_DCHECK(sid.has_value() || !role); return RTCError::OK();
}
// RTC_RUN_ON(network_thread())
RTCErrorOr<rtc::scoped_refptr<SctpDataChannel>>
DataChannelController::CreateDataChannel(const std::string& label,
InternalDataChannelInit& config) {
std::optional<StreamId> sid = std::nullopt; if (config.id != -1) { if (config.id < 0 || config.id > cricket::kMaxSctpSid) { return RTCError(RTCErrorType::INVALID_RANGE, "StreamId out of range.");
}
sid = StreamId(config.id);
}
RTCError err = ReserveOrAllocateSid(sid, config.fallback_ssl_role); if (!err.ok()) return err;
// In case `sid` has changed. Update `config` accordingly. if (sid.has_value()) {
config.id = sid->stream_id_int();
}
// If we have an id already, notify the transport. if (sid.has_value())
AddSctpDataStream(*sid,
config.priority.value_or(PriorityValue(Priority::kLow)));
bool ready_to_send = false;
InternalDataChannelInit new_config = config; auto ret = network_thread()->BlockingCall(
[&]() -> RTCErrorOr<rtc::scoped_refptr<SctpDataChannel>> {
RTC_DCHECK_RUN_ON(network_thread()); auto channel = CreateDataChannel(label, new_config); if (!channel.ok()) return channel;
ready_to_send =
data_channel_transport_ && data_channel_transport_->IsReadyToSend(); if (ready_to_send) { // 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 // `InternalCreateDataChannelWithProxy` returns.
network_thread()->PostTask([channel = channel.value()] { if (channel->state() != DataChannelInterface::DataState::kClosed)
channel->OnTransportReady();
});
}
std::vector<std::pair<SctpDataChannel*, StreamId>> channels_to_update;
std::vector<rtc::scoped_refptr<SctpDataChannel>> channels_to_close; for (auto it = sctp_data_channels_n_.begin();
it != sctp_data_channels_n_.end();) { if (!(*it)->sid_n().has_value()) {
std::optional<StreamId> sid = sid_allocator_.AllocateSid(role); if (sid.has_value()) {
(*it)->SetSctpSid_n(*sid);
AddSctpDataStream(*sid, (*it)->priority()); if (ready_to_send) {
RTC_LOG(LS_INFO) << "AllocateSctpSids: Id assigned, ready to send.";
(*it)->OnTransportReady();
}
channels_to_update.push_back(std::make_pair((*it).get(), *sid));
} else {
channels_to_close.push_back(std::move(*it));
it = sctp_data_channels_n_.erase(it); continue;
}
}
++it;
}
// Since closing modifies the list of channels, we have to do the actual // closing outside the loop. for (constauto& channel : channels_to_close) {
channel->CloseAbruptlyWithDataChannelFailure("Failed to allocate SCTP SID");
}
}
void DataChannelController::OnSctpDataChannelClosed(SctpDataChannel* channel) {
RTC_DCHECK_RUN_ON(network_thread()); // After the closing procedure is done, it's safe to use this ID for // another data channel. if (channel->sid_n().has_value()) {
sid_allocator_.ReleaseSid(*channel->sid_n());
} auto it = absl::c_find_if(sctp_data_channels_n_,
[&](constauto& c) { return c.get() == channel; }); if (it != sctp_data_channels_n_.end())
sctp_data_channels_n_.erase(it);
}
if (data_channel_transport_)
data_channel_transport_->SetDataSink(nullptr);
data_channel_transport_ = transport;
if (data_channel_transport_) { // There's a new data channel transport. This needs to be signaled to the // `sctp_data_channels_n_` so that they can reopen and reconnect. This is // necessary when bundling is applied.
NotifyDataChannelsOfTransportCreated();
data_channel_transport_->SetDataSink(this);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.