From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- .../p2p/base/wrapping_active_ice_controller.cc | 253 +++++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 third_party/libwebrtc/p2p/base/wrapping_active_ice_controller.cc (limited to 'third_party/libwebrtc/p2p/base/wrapping_active_ice_controller.cc') diff --git a/third_party/libwebrtc/p2p/base/wrapping_active_ice_controller.cc b/third_party/libwebrtc/p2p/base/wrapping_active_ice_controller.cc new file mode 100644 index 0000000000..c6659217fc --- /dev/null +++ b/third_party/libwebrtc/p2p/base/wrapping_active_ice_controller.cc @@ -0,0 +1,253 @@ +/* + * Copyright 2022 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. + */ + +#include "p2p/base/wrapping_active_ice_controller.h" + +#include +#include +#include + +#include "api/sequence_checker.h" +#include "api/task_queue/pending_task_safety_flag.h" +#include "api/units/time_delta.h" +#include "p2p/base/basic_ice_controller.h" +#include "p2p/base/connection.h" +#include "p2p/base/ice_agent_interface.h" +#include "p2p/base/ice_controller_interface.h" +#include "p2p/base/ice_switch_reason.h" +#include "p2p/base/ice_transport_internal.h" +#include "p2p/base/transport_description.h" +#include "rtc_base/logging.h" +#include "rtc_base/thread.h" +#include "rtc_base/time_utils.h" + +namespace { +using ::webrtc::SafeTask; +using ::webrtc::TimeDelta; +} // unnamed namespace + +namespace cricket { + +WrappingActiveIceController::WrappingActiveIceController( + IceAgentInterface* ice_agent, + std::unique_ptr wrapped) + : network_thread_(rtc::Thread::Current()), + wrapped_(std::move(wrapped)), + agent_(*ice_agent) { + RTC_DCHECK(ice_agent != nullptr); +} + +WrappingActiveIceController::WrappingActiveIceController( + IceAgentInterface* ice_agent, + IceControllerFactoryInterface* wrapped_factory, + const IceControllerFactoryArgs& wrapped_factory_args) + : network_thread_(rtc::Thread::Current()), agent_(*ice_agent) { + RTC_DCHECK(ice_agent != nullptr); + if (wrapped_factory) { + wrapped_ = wrapped_factory->Create(wrapped_factory_args); + } else { + wrapped_ = std::make_unique(wrapped_factory_args); + } +} + +WrappingActiveIceController::~WrappingActiveIceController() {} + +void WrappingActiveIceController::SetIceConfig(const IceConfig& config) { + RTC_DCHECK_RUN_ON(network_thread_); + wrapped_->SetIceConfig(config); +} + +bool WrappingActiveIceController::GetUseCandidateAttribute( + const Connection* connection, + NominationMode mode, + IceMode remote_ice_mode) const { + RTC_DCHECK_RUN_ON(network_thread_); + return wrapped_->GetUseCandidateAttr(connection, mode, remote_ice_mode); +} + +void WrappingActiveIceController::OnConnectionAdded( + const Connection* connection) { + RTC_DCHECK_RUN_ON(network_thread_); + wrapped_->AddConnection(connection); +} + +void WrappingActiveIceController::OnConnectionPinged( + const Connection* connection) { + RTC_DCHECK_RUN_ON(network_thread_); + wrapped_->MarkConnectionPinged(connection); +} + +void WrappingActiveIceController::OnConnectionUpdated( + const Connection* connection) { + RTC_LOG(LS_VERBOSE) << "Connection report for " << connection->ToString(); + // Do nothing. Native ICE controllers have direct access to Connection, so no + // need to update connection state separately. +} + +void WrappingActiveIceController::OnConnectionSwitched( + const Connection* connection) { + RTC_DCHECK_RUN_ON(network_thread_); + selected_connection_ = connection; + wrapped_->SetSelectedConnection(connection); +} + +void WrappingActiveIceController::OnConnectionDestroyed( + const Connection* connection) { + RTC_DCHECK_RUN_ON(network_thread_); + wrapped_->OnConnectionDestroyed(connection); +} + +void WrappingActiveIceController::MaybeStartPinging() { + RTC_DCHECK_RUN_ON(network_thread_); + if (started_pinging_) { + return; + } + + if (wrapped_->HasPingableConnection()) { + network_thread_->PostTask( + SafeTask(task_safety_.flag(), [this]() { SelectAndPingConnection(); })); + agent_.OnStartedPinging(); + started_pinging_ = true; + } +} + +void WrappingActiveIceController::SelectAndPingConnection() { + RTC_DCHECK_RUN_ON(network_thread_); + agent_.UpdateConnectionStates(); + + IceControllerInterface::PingResult result = + wrapped_->SelectConnectionToPing(agent_.GetLastPingSentMs()); + HandlePingResult(result); +} + +void WrappingActiveIceController::HandlePingResult( + IceControllerInterface::PingResult result) { + RTC_DCHECK_RUN_ON(network_thread_); + + if (result.connection.has_value()) { + agent_.SendPingRequest(result.connection.value()); + } + + network_thread_->PostDelayedTask( + SafeTask(task_safety_.flag(), [this]() { SelectAndPingConnection(); }), + TimeDelta::Millis(result.recheck_delay_ms)); +} + +void WrappingActiveIceController::OnSortAndSwitchRequest( + IceSwitchReason reason) { + RTC_DCHECK_RUN_ON(network_thread_); + if (!sort_pending_) { + network_thread_->PostTask(SafeTask(task_safety_.flag(), [this, reason]() { + SortAndSwitchToBestConnection(reason); + })); + sort_pending_ = true; + } +} + +void WrappingActiveIceController::OnImmediateSortAndSwitchRequest( + IceSwitchReason reason) { + RTC_DCHECK_RUN_ON(network_thread_); + SortAndSwitchToBestConnection(reason); +} + +void WrappingActiveIceController::SortAndSwitchToBestConnection( + IceSwitchReason reason) { + RTC_DCHECK_RUN_ON(network_thread_); + + // Make sure the connection states are up-to-date since this affects how they + // will be sorted. + agent_.UpdateConnectionStates(); + + // Any changes after this point will require a re-sort. + sort_pending_ = false; + + IceControllerInterface::SwitchResult result = + wrapped_->SortAndSwitchConnection(reason); + HandleSwitchResult(reason, result); + UpdateStateOnConnectionsResorted(); +} + +bool WrappingActiveIceController::OnImmediateSwitchRequest( + IceSwitchReason reason, + const Connection* selected) { + RTC_DCHECK_RUN_ON(network_thread_); + IceControllerInterface::SwitchResult result = + wrapped_->ShouldSwitchConnection(reason, selected); + HandleSwitchResult(reason, result); + return result.connection.has_value(); +} + +void WrappingActiveIceController::HandleSwitchResult( + IceSwitchReason reason_for_switch, + IceControllerInterface::SwitchResult result) { + RTC_DCHECK_RUN_ON(network_thread_); + if (result.connection.has_value()) { + RTC_LOG(LS_INFO) << "Switching selected connection due to: " + << IceSwitchReasonToString(reason_for_switch); + agent_.SwitchSelectedConnection(result.connection.value(), + reason_for_switch); + } + + if (result.recheck_event.has_value()) { + // If we do not switch to the connection because it missed the receiving + // threshold, the new connection is in a better receiving state than the + // currently selected connection. So we need to re-check whether it needs + // to be switched at a later time. + network_thread_->PostDelayedTask( + SafeTask(task_safety_.flag(), + [this, recheck_reason = result.recheck_event->reason]() { + SortAndSwitchToBestConnection(recheck_reason); + }), + TimeDelta::Millis(result.recheck_event->recheck_delay_ms)); + } + + agent_.ForgetLearnedStateForConnections( + result.connections_to_forget_state_on); +} + +void WrappingActiveIceController::UpdateStateOnConnectionsResorted() { + RTC_DCHECK_RUN_ON(network_thread_); + PruneConnections(); + + // Update the internal state of the ICE agentl. + agent_.UpdateState(); + + // Also possibly start pinging. + // We could start pinging if: + // * The first connection was created. + // * ICE credentials were provided. + // * A TCP connection became connected. + MaybeStartPinging(); +} + +void WrappingActiveIceController::PruneConnections() { + RTC_DCHECK_RUN_ON(network_thread_); + + // The controlled side can prune only if the selected connection has been + // nominated because otherwise it may prune the connection that will be + // selected by the controlling side. + // TODO(honghaiz): This is not enough to prevent a connection from being + // pruned too early because with aggressive nomination, the controlling side + // will nominate every connection until it becomes writable. + if (agent_.GetIceRole() == ICEROLE_CONTROLLING || + (selected_connection_ && selected_connection_->nominated())) { + std::vector connections_to_prune = + wrapped_->PruneConnections(); + agent_.PruneConnections(connections_to_prune); + } +} + +// Only for unit tests +const Connection* WrappingActiveIceController::FindNextPingableConnection() { + RTC_DCHECK_RUN_ON(network_thread_); + return wrapped_->FindNextPingableConnection(); +} + +} // namespace cricket -- cgit v1.2.3