Revert "Refactor the regathering of candidates in P2PTransportChannel."

This reverts commit 14f8aba9967ac2f1789ede12ff66107962757fb5.

Reason for revert: breaking internal tests

Original change's description:
> Refactor the regathering of candidates in P2PTransportChannel.
> 
> The functionality of regathering candidates is refactored to a separate
> regathering controller owned by P2PTransportChannel. This refactoring
> is part of a long-term plan to restructure a modularied
> P2PTransportChannel and it would also benefit the addition of autonomous
> regathering of candidates that is proactive to the ICE states in the
> near future.
> 
> Bug: None
> Change-Id: I74cea974ea628430c77b5d51b7c9179ddffc690d
> Reviewed-on: https://webrtc-review.googlesource.com/75820
> Commit-Queue: Qingsi Wang <qingsi@google.com>
> Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#23588}

TBR=deadbeef@webrtc.org,pthatcher@webrtc.org,qingsi@google.com

Change-Id: I8b08351c9a3fcf89e2a25ed2c668c335cbd2d2d0
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: None
Reviewed-on: https://webrtc-review.googlesource.com/83300
Reviewed-by: Qingsi Wang <qingsi@webrtc.org>
Commit-Queue: Qingsi Wang <qingsi@google.com>
Cr-Commit-Position: refs/heads/master@{#23592}
This commit is contained in:
Qingsi Wang
2018-06-13 05:54:43 +00:00
committed by Commit Bot
parent 241d0c16c0
commit 1f4d7a2848
7 changed files with 55 additions and 626 deletions

View File

@ -48,8 +48,6 @@ rtc_static_library("rtc_p2p") {
"base/portinterface.h",
"base/pseudotcp.cc",
"base/pseudotcp.h",
"base/regatheringcontroller.cc",
"base/regatheringcontroller.h",
"base/relayport.cc",
"base/relayport.h",
"base/stun.cc",
@ -151,7 +149,6 @@ if (rtc_include_tests) {
"base/port_unittest.cc",
"base/portallocator_unittest.cc",
"base/pseudotcp_unittest.cc",
"base/regatheringcontroller_unittest.cc",
"base/relayport_unittest.cc",
"base/relayserver_unittest.cc",
"base/stun_unittest.cc",

View File

@ -139,16 +139,7 @@ class FakePortAllocatorSession : public PortAllocatorSession {
void StopGettingPorts() override { running_ = false; }
bool IsGettingPorts() override { return running_; }
void ClearGettingPorts() override { is_cleared = true; }
bool IsCleared() const override { return is_cleared; }
void RegatherOnAllNetworks() override {
SignalIceRegathering(this, IceRegatheringReason::OCCASIONAL_REFRESH);
}
void RegatherOnFailedNetworks() override {
SignalIceRegathering(this, IceRegatheringReason::NETWORK_FAILURE);
}
void ClearGettingPorts() override {}
std::vector<PortInterface*> ReadyPorts() const override {
return ready_ports_;
@ -213,7 +204,6 @@ class FakePortAllocatorSession : public PortAllocatorSession {
std::vector<Candidate> candidates_;
std::vector<PortInterface*> ready_ports_;
bool allocation_done_ = false;
bool is_cleared = false;
ServerAddresses stun_servers_;
std::vector<RelayServerConfig> turn_servers_;
uint32_t candidate_filter_ = CF_ALL;

View File

@ -125,6 +125,7 @@ P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
ice_role_(ICEROLE_UNKNOWN),
tiebreaker_(0),
gathering_state_(kIceGatheringNew),
rand_(rtc::SystemTimeNanos()),
config_(RECEIVING_TIMEOUT,
BACKUP_CONNECTION_PING_INTERVAL,
GATHER_ONCE /* continual_gathering_policy */,
@ -137,11 +138,6 @@ P2PTransportChannel::P2PTransportChannel(const std::string& transport_name,
// Validate IceConfig even for mostly built-in constant default values in case
// we change them.
RTC_DCHECK(ValidateIceConfig(config_).ok());
webrtc::BasicRegatheringController::Config regathering_config(
config_.regather_all_networks_interval_range,
config_.regather_on_failed_networks_interval_or_default());
regathering_controller_.reset(new webrtc::BasicRegatheringController(
regathering_config, this, network_thread_));
ice_event_log_.set_event_log(event_log);
}
@ -168,7 +164,6 @@ void P2PTransportChannel::AddAllocatorSession(
allocator_session()->PruneAllPorts();
}
allocator_sessions_.push_back(std::move(session));
regathering_controller_->set_allocator_session(allocator_session());
// We now only want to apply new candidates that we receive to the ports
// created by this new session because these are replacing those of the
@ -576,11 +571,6 @@ void P2PTransportChannel::SetIceConfig(const IceConfig& config) {
<< config.stun_keepalive_interval_or_default();
}
webrtc::BasicRegatheringController::Config regathering_config(
config_.regather_all_networks_interval_range,
config_.regather_on_failed_networks_interval_or_default());
regathering_controller_->SetConfig(regathering_config);
RTC_DCHECK(ValidateIceConfig(config_).ok());
}
@ -588,8 +578,6 @@ const IceConfig& P2PTransportChannel::config() const {
return config_;
}
// TODO(qingsi): Add tests for the config validation starting from
// PeerConnection::SetConfiguration.
RTCError P2PTransportChannel::ValidateIceConfig(const IceConfig& config) {
if (config.regather_all_networks_interval_range &&
config.continual_gathering_policy == GATHER_ONCE) {
@ -637,13 +625,6 @@ RTCError P2PTransportChannel::ValidateIceConfig(const IceConfig& config) {
"UNRELIABLE is longer than that to become TIMEOUT.");
}
if (config.regather_all_networks_interval_range &&
config.regather_all_networks_interval_range.value().min() < 0) {
return RTCError(
RTCErrorType::INVALID_RANGE,
"The minimum regathering interval for all networks is negative.");
}
return RTCError::OK();
}
@ -1311,7 +1292,16 @@ void P2PTransportChannel::MaybeStartPinging() {
invoker_.AsyncInvoke<void>(
RTC_FROM_HERE, thread(),
rtc::Bind(&P2PTransportChannel::CheckAndPing, this));
regathering_controller_->Start();
invoker_.AsyncInvokeDelayed<void>(
RTC_FROM_HERE, thread(),
rtc::Bind(&P2PTransportChannel::RegatherOnFailedNetworks, this),
config_.regather_on_failed_networks_interval_or_default());
if (config_.regather_all_networks_interval_range) {
invoker_.AsyncInvokeDelayed<void>(
RTC_FROM_HERE, thread(),
rtc::Bind(&P2PTransportChannel::RegatherOnAllNetworks, this),
SampleRegatherAllNetworksInterval());
}
started_pinging_ = true;
}
}
@ -2195,6 +2185,31 @@ void P2PTransportChannel::OnCandidatesRemoved(
SignalCandidatesRemoved(this, candidates_to_remove);
}
void P2PTransportChannel::RegatherOnFailedNetworks() {
// Only re-gather when the current session is in the CLEARED state (i.e., not
// running or stopped). It is only possible to enter this state when we gather
// continually, so there is an implicit check on continual gathering here.
if (!allocator_sessions_.empty() && allocator_session()->IsCleared()) {
allocator_session()->RegatherOnFailedNetworks();
}
invoker_.AsyncInvokeDelayed<void>(
RTC_FROM_HERE, thread(),
rtc::Bind(&P2PTransportChannel::RegatherOnFailedNetworks, this),
config_.regather_on_failed_networks_interval_or_default());
}
void P2PTransportChannel::RegatherOnAllNetworks() {
if (!allocator_sessions_.empty() && allocator_session()->IsCleared()) {
allocator_session()->RegatherOnAllNetworks();
}
invoker_.AsyncInvokeDelayed<void>(
RTC_FROM_HERE, thread(),
rtc::Bind(&P2PTransportChannel::RegatherOnAllNetworks, this),
SampleRegatherAllNetworksInterval());
}
void P2PTransportChannel::PruneAllPorts() {
pruned_ports_.insert(pruned_ports_.end(), ports_.begin(), ports_.end());
ports_.clear();
@ -2348,6 +2363,12 @@ void P2PTransportChannel::set_receiving(bool receiving) {
SignalReceivingState(this);
}
int P2PTransportChannel::SampleRegatherAllNetworksInterval() {
auto interval = config_.regather_all_networks_interval_range;
RTC_DCHECK(interval);
return rand_.Rand(interval->min(), interval->max());
}
void P2PTransportChannel::LogCandidatePairConfig(
Connection* conn,
webrtc::IceCandidatePairConfigType type) {

View File

@ -36,10 +36,10 @@
#include "p2p/base/p2pconstants.h"
#include "p2p/base/portallocator.h"
#include "p2p/base/portinterface.h"
#include "p2p/base/regatheringcontroller.h"
#include "rtc_base/asyncinvoker.h"
#include "rtc_base/asyncpacketsocket.h"
#include "rtc_base/constructormagic.h"
#include "rtc_base/random.h"
#include "rtc_base/sigslot.h"
namespace webrtc {
@ -151,10 +151,7 @@ class P2PTransportChannel : public IceTransportInternal {
const std::vector<Connection*>& connections() const { return connections_; }
// Public for unit tests.
PortAllocatorSession* allocator_session() const {
if (allocator_sessions_.empty()) {
return nullptr;
}
PortAllocatorSession* allocator_session() {
return allocator_sessions_.back().get();
}
@ -174,7 +171,6 @@ class P2PTransportChannel : public IceTransportInternal {
private:
rtc::Thread* thread() const { return network_thread_; }
bool IsGettingPorts() { return allocator_session()->IsGettingPorts(); }
// A transport channel is weak if the current best connection is either
@ -293,6 +289,8 @@ class P2PTransportChannel : public IceTransportInternal {
void OnNominated(Connection* conn);
void CheckAndPing();
void RegatherOnFailedNetworks();
void RegatherOnAllNetworks();
void LogCandidatePairConfig(Connection* conn,
webrtc::IceCandidatePairConfigType type);
@ -344,6 +342,10 @@ class P2PTransportChannel : public IceTransportInternal {
: static_cast<uint32_t>(remote_ice_parameters_.size() - 1);
}
// Samples a delay from the uniform distribution defined by the
// regather_on_all_networks_interval ICE configuration pair.
int SampleRegatherAllNetworksInterval();
// Indicates if the given local port has been pruned.
bool IsPortPruned(const Port* port) const;
@ -393,7 +395,10 @@ class P2PTransportChannel : public IceTransportInternal {
IceRole ice_role_;
uint64_t tiebreaker_;
IceGatheringState gathering_state_;
std::unique_ptr<webrtc::BasicRegatheringController> regathering_controller_;
// Used to generate random intervals for regather_all_networks_interval_range.
webrtc::Random rand_;
int64_t last_ping_sent_ms_ = 0;
int weak_ping_interval_ = WEAK_PING_INTERVAL;
IceTransportState state_ = IceTransportState::STATE_INIT;

View File

@ -1,157 +0,0 @@
/*
* Copyright 2018 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/regatheringcontroller.h"
namespace webrtc {
using Config = BasicRegatheringController::Config;
Config::Config(const rtc::Optional<rtc::IntervalRange>&
regather_on_all_networks_interval_range,
int regather_on_failed_networks_interval)
: regather_on_all_networks_interval_range(
regather_on_all_networks_interval_range),
regather_on_failed_networks_interval(
regather_on_failed_networks_interval) {}
Config::Config(const Config& other) = default;
Config::~Config() = default;
Config& Config::operator=(const Config& other) = default;
BasicRegatheringController::BasicRegatheringController(
const Config& config,
cricket::IceTransportInternal* ice_transport,
rtc::Thread* thread)
: config_(config),
ice_transport_(ice_transport),
thread_(thread),
rand_(rtc::SystemTimeNanos()) {
RTC_DCHECK(ice_transport_);
RTC_DCHECK(thread_);
ice_transport_->SignalStateChanged.connect(
this, &BasicRegatheringController::OnIceTransportStateChanged);
ice_transport->SignalWritableState.connect(
this, &BasicRegatheringController::OnIceTransportWritableState);
ice_transport->SignalReceivingState.connect(
this, &BasicRegatheringController::OnIceTransportReceivingState);
ice_transport->SignalNetworkRouteChanged.connect(
this, &BasicRegatheringController::OnIceTransportNetworkRouteChanged);
}
BasicRegatheringController::~BasicRegatheringController() = default;
void BasicRegatheringController::Start() {
ScheduleRecurringRegatheringOnFailedNetworks();
if (config_.regather_on_all_networks_interval_range) {
ScheduleRecurringRegatheringOnAllNetworks();
}
}
void BasicRegatheringController::SetConfig(const Config& config) {
bool need_cancel_on_all_networks =
has_recurring_schedule_on_all_networks_ &&
(config_.regather_on_all_networks_interval_range !=
config.regather_on_all_networks_interval_range);
bool need_reschedule_on_all_networks =
config.regather_on_all_networks_interval_range &&
(config_.regather_on_all_networks_interval_range !=
config.regather_on_all_networks_interval_range);
bool need_cancel_and_reschedule_on_failed_networks =
has_recurring_schedule_on_failed_networks_ &&
(config_.regather_on_failed_networks_interval !=
config.regather_on_failed_networks_interval);
config_ = config;
if (need_cancel_on_all_networks) {
CancelScheduledRecurringRegatheringOnAllNetworks();
}
if (need_reschedule_on_all_networks) {
ScheduleRecurringRegatheringOnAllNetworks();
}
if (need_cancel_and_reschedule_on_failed_networks) {
CancelScheduledRecurringRegatheringOnFailedNetworks();
ScheduleRecurringRegatheringOnFailedNetworks();
}
}
void BasicRegatheringController::ScheduleRecurringRegatheringOnAllNetworks() {
RTC_DCHECK(config_.regather_on_all_networks_interval_range &&
config_.regather_on_all_networks_interval_range.value().min() >=
0);
int delay_ms = SampleRegatherAllNetworksInterval(
config_.regather_on_all_networks_interval_range.value());
CancelScheduledRecurringRegatheringOnAllNetworks();
has_recurring_schedule_on_all_networks_ = true;
invoker_for_all_networks_.AsyncInvokeDelayed<void>(
RTC_FROM_HERE, thread(),
rtc::Bind(
&BasicRegatheringController::RegatherOnAllNetworksIfDoneGathering,
this, true),
delay_ms);
}
void BasicRegatheringController::RegatherOnAllNetworksIfDoneGathering(
bool repeated) {
// Only regather when the current session is in the CLEARED state (i.e., not
// running or stopped). It is only possible to enter this state when we gather
// continually, so there is an implicit check on continual gathering here.
if (allocator_session_ && allocator_session_->IsCleared()) {
allocator_session_->RegatherOnAllNetworks();
}
if (repeated) {
ScheduleRecurringRegatheringOnAllNetworks();
}
}
void BasicRegatheringController::
ScheduleRecurringRegatheringOnFailedNetworks() {
RTC_DCHECK(config_.regather_on_failed_networks_interval >= 0);
CancelScheduledRecurringRegatheringOnFailedNetworks();
has_recurring_schedule_on_failed_networks_ = true;
invoker_for_failed_networks_.AsyncInvokeDelayed<void>(
RTC_FROM_HERE, thread(),
rtc::Bind(
&BasicRegatheringController::RegatherOnFailedNetworksIfDoneGathering,
this, true),
config_.regather_on_failed_networks_interval);
}
void BasicRegatheringController::RegatherOnFailedNetworksIfDoneGathering(
bool repeated) {
// Only regather when the current session is in the CLEARED state (i.e., not
// running or stopped). It is only possible to enter this state when we gather
// continually, so there is an implicit check on continual gathering here.
if (allocator_session_ && allocator_session_->IsCleared()) {
allocator_session_->RegatherOnFailedNetworks();
}
if (repeated) {
ScheduleRecurringRegatheringOnFailedNetworks();
}
}
void BasicRegatheringController::
CancelScheduledRecurringRegatheringOnAllNetworks() {
invoker_for_all_networks_.Clear();
has_recurring_schedule_on_all_networks_ = false;
}
void BasicRegatheringController::
CancelScheduledRecurringRegatheringOnFailedNetworks() {
invoker_for_failed_networks_.Clear();
has_recurring_schedule_on_failed_networks_ = false;
}
int BasicRegatheringController::SampleRegatherAllNetworksInterval(
const rtc::IntervalRange& range) {
return rand_.Rand(range.min(), range.max());
}
} // namespace webrtc

View File

@ -1,124 +0,0 @@
/*
* Copyright 2018 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.
*/
#ifndef P2P_BASE_REGATHERINGCONTROLLER_H_
#define P2P_BASE_REGATHERINGCONTROLLER_H_
#include "p2p/base/icetransportinternal.h"
#include "p2p/base/portallocator.h"
#include "rtc_base/asyncinvoker.h"
#include "rtc_base/random.h"
#include "rtc_base/thread.h"
namespace webrtc {
// Controls regathering of candidates for the ICE transport passed into it,
// reacting to signals like SignalWritableState, SignalNetworkRouteChange, etc.,
// using methods like GetStats to get additional information, and calling
// methods like RegatherOnAllNetworks on the PortAllocatorSession when
// regathering is desired.
//
// TODO(qingsi): Add the description of behavior when autonomous regathering is
// implemented.
//
// "Regathering" is defined as gathering additional candidates within a single
// ICE generation (or in other words, PortAllocatorSession), and is possible
// when "continual gathering" is enabled. This may allow connectivity to be
// maintained and/or restored without a full ICE restart.
//
// Regathering will only begin after PortAllocationSession is set via
// set_allocator_session. This should be called any time the "active"
// PortAllocatorSession is changed (in other words, when an ICE restart occurs),
// so that candidates are gathered for the "current" ICE generation.
//
// All methods of BasicRegatheringController should be called on the same
// thread as the one passed to the constructor, and this thread should be the
// same one where PortAllocatorSession runs, which is also identical to the
// network thread of the ICE transport, as given by
// P2PTransportChannel::thread().
class BasicRegatheringController : public sigslot::has_slots<> {
public:
struct Config {
Config(const rtc::Optional<rtc::IntervalRange>&
regather_on_all_networks_interval_range,
int regather_on_failed_networks_interval);
Config(const Config& other);
~Config();
Config& operator=(const Config& other);
rtc::Optional<rtc::IntervalRange> regather_on_all_networks_interval_range;
int regather_on_failed_networks_interval;
};
BasicRegatheringController() = delete;
BasicRegatheringController(const Config& config,
cricket::IceTransportInternal* ice_transport,
rtc::Thread* thread);
~BasicRegatheringController() override;
// TODO(qingsi): Remove this method after implementing a new signal in
// P2PTransportChannel and reacting to that signal for the initial schedules
// of regathering.
void Start();
void set_allocator_session(cricket::PortAllocatorSession* allocator_session) {
allocator_session_ = allocator_session;
}
// Setting a different config of the regathering interval range on all
// networks cancels and reschedules the recurring schedules, if any, of
// regathering on all networks. The same applies to the change of the
// regathering interval on the failed networks. This rescheduling behavior is
// seperately defined for the two config parameters.
void SetConfig(const Config& config);
private:
// TODO(qingsi): Implement the following methods and use methods from the ICE
// transport like GetStats to get additional information for the decision
// making in regathering.
void OnIceTransportStateChanged(cricket::IceTransportInternal*) {}
void OnIceTransportWritableState(rtc::PacketTransportInternal*) {}
void OnIceTransportReceivingState(rtc::PacketTransportInternal*) {}
void OnIceTransportNetworkRouteChanged(rtc::Optional<rtc::NetworkRoute>) {}
// Schedules delayed and repeated regathering of local candidates on all
// networks, where the delay in milliseconds is randomly sampled from the
// range in the config. The delay of each repetition is independently sampled
// from the same range. When scheduled, all previous schedules are canceled.
void ScheduleRecurringRegatheringOnAllNetworks();
// Schedules delayed and repeated regathering of local candidates on failed
// networks, where the delay in milliseconds is given by the config. Each
// repetition is separated by the same delay. When scheduled, all previous
// schedules are canceled.
void ScheduleRecurringRegatheringOnFailedNetworks();
// Cancels regathering scheduled by ScheduleRecurringRegatheringOnAllNetworks.
void CancelScheduledRecurringRegatheringOnAllNetworks();
// Cancels regathering scheduled by
// ScheduleRecurringRegatheringOnFailedNetworks.
void CancelScheduledRecurringRegatheringOnFailedNetworks();
rtc::Thread* thread() const { return thread_; }
// The following two methods perform the actual regathering, if the recent
// port allocator session has done the initial gathering.
void RegatherOnAllNetworksIfDoneGathering(bool repeated);
void RegatherOnFailedNetworksIfDoneGathering(bool repeated);
// Samples a delay from the uniform distribution in the given range.
int SampleRegatherAllNetworksInterval(const rtc::IntervalRange& range);
Config config_;
cricket::IceTransportInternal* ice_transport_;
cricket::PortAllocatorSession* allocator_session_ = nullptr;
bool has_recurring_schedule_on_all_networks_ = false;
bool has_recurring_schedule_on_failed_networks_ = false;
rtc::Thread* thread_;
rtc::AsyncInvoker invoker_for_all_networks_;
rtc::AsyncInvoker invoker_for_failed_networks_;
// Used to generate random intervals for regather_all_networks_interval_range.
Random rand_;
};
} // namespace webrtc
#endif // P2P_BASE_REGATHERINGCONTROLLER_H_

View File

@ -1,303 +0,0 @@
/*
* Copyright 2018 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 <map>
#include <memory>
#include <string>
#include <vector>
#include "api/fakemetricsobserver.h"
#include "p2p/base/fakeportallocator.h"
#include "p2p/base/mockicetransport.h"
#include "p2p/base/p2pconstants.h"
#include "p2p/base/port.h"
#include "p2p/base/regatheringcontroller.h"
#include "p2p/base/stunserver.h"
#include "rtc_base/gunit.h"
#include "rtc_base/refcountedobject.h"
#include "rtc_base/scoped_ref_ptr.h"
#include "rtc_base/socketaddress.h"
#include "rtc_base/thread.h"
namespace {
const int kOnlyLocalPorts = cricket::PORTALLOCATOR_DISABLE_STUN |
cricket::PORTALLOCATOR_DISABLE_RELAY |
cricket::PORTALLOCATOR_DISABLE_TCP;
// The address of the public STUN server.
const rtc::SocketAddress kStunAddr("99.99.99.1", cricket::STUN_SERVER_PORT);
// The addresses for the public TURN server.
const rtc::SocketAddress kTurnUdpIntAddr("99.99.99.3",
cricket::STUN_SERVER_PORT);
const cricket::RelayCredentials kRelayCredentials("test", "test");
const char kIceUfrag[] = "UF00";
const char kIcePwd[] = "TESTICEPWD00000000000000";
} // namespace
namespace webrtc {
class RegatheringControllerTest : public testing::Test,
public sigslot::has_slots<> {
public:
RegatheringControllerTest()
: ice_transport_(new cricket::MockIceTransport()),
allocator_(
new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr)) {
BasicRegatheringController::Config regathering_config(rtc::nullopt, 0);
regathering_controller_.reset(new BasicRegatheringController(
regathering_config, ice_transport_.get(), rtc::Thread::Current()));
}
// Initializes the allocator and gathers candidates once by StartGettingPorts.
void InitializeAndGatherOnce() {
cricket::ServerAddresses stun_servers;
stun_servers.insert(kStunAddr);
cricket::RelayServerConfig turn_server(cricket::RELAY_TURN);
turn_server.credentials = kRelayCredentials;
turn_server.ports.push_back(
cricket::ProtocolAddress(kTurnUdpIntAddr, cricket::PROTO_UDP));
std::vector<cricket::RelayServerConfig> turn_servers(1, turn_server);
allocator_->set_flags(kOnlyLocalPorts);
allocator_->SetConfiguration(stun_servers, turn_servers, 0 /* pool size */,
false /* prune turn ports */);
allocator_session_ = allocator_->CreateSession(
"test", cricket::ICE_CANDIDATE_COMPONENT_RTP, kIceUfrag, kIcePwd);
// The gathering will take place on the current thread and the following
// call of StartGettingPorts is blocking. We will not ClearGettingPorts
// prematurely.
allocator_session_->StartGettingPorts();
allocator_session_->SignalIceRegathering.connect(
this, &RegatheringControllerTest::OnIceRegathering);
regathering_controller_->set_allocator_session(allocator_session_.get());
}
// The regathering controller is initialized with the allocator session
// cleared. Only after clearing the session, we would be able to regather. See
// the comments for BasicRegatheringController in regatheringcontroller.h.
void InitializeAndGatherOnceWithSessionCleared() {
InitializeAndGatherOnce();
allocator_session_->ClearGettingPorts();
}
void OnIceRegathering(cricket::PortAllocatorSession* allocator_session,
cricket::IceRegatheringReason reason) {
++count_[reason];
}
int GetRegatheringReasonCount(cricket::IceRegatheringReason reason) {
return count_[reason];
}
BasicRegatheringController* regathering_controller() {
return regathering_controller_.get();
}
private:
std::unique_ptr<cricket::IceTransportInternal> ice_transport_;
std::unique_ptr<BasicRegatheringController> regathering_controller_;
std::unique_ptr<cricket::PortAllocator> allocator_;
std::unique_ptr<cricket::PortAllocatorSession> allocator_session_;
std::map<cricket::IceRegatheringReason, int> count_;
};
// Tests that ICE regathering occurs only if the port allocator session is
// cleared. A port allocation session is not cleared if the initial gathering is
// still in progress or the continual gathering is not enabled.
TEST_F(RegatheringControllerTest,
IceRegatheringDoesNotOccurIfSessionNotCleared) {
rtc::ScopedFakeClock clock;
InitializeAndGatherOnce(); // Session not cleared.
rtc::IntervalRange regather_all_networks_interval_range(2000, 2000);
BasicRegatheringController::Config config(
regather_all_networks_interval_range, 2000);
regathering_controller()->SetConfig(config);
regathering_controller()->Start();
SIMULATED_WAIT(false, 10000, clock);
// Expect no regathering in the last 10s.
EXPECT_EQ(0, GetRegatheringReasonCount(
cricket::IceRegatheringReason::OCCASIONAL_REFRESH));
EXPECT_EQ(0, GetRegatheringReasonCount(
cricket::IceRegatheringReason::NETWORK_FAILURE));
}
TEST_F(RegatheringControllerTest, IceRegatheringRepeatsAsScheduled) {
rtc::ScopedFakeClock clock;
InitializeAndGatherOnceWithSessionCleared();
rtc::IntervalRange regather_all_networks_interval_range(2000, 2000);
BasicRegatheringController::Config config(
regather_all_networks_interval_range, 2000);
regathering_controller()->SetConfig(config);
regathering_controller()->Start();
SIMULATED_WAIT(false, 2000 - 1, clock);
// Expect no regathering.
EXPECT_EQ(0, GetRegatheringReasonCount(
cricket::IceRegatheringReason::OCCASIONAL_REFRESH));
EXPECT_EQ(0, GetRegatheringReasonCount(
cricket::IceRegatheringReason::NETWORK_FAILURE));
SIMULATED_WAIT(false, 2, clock);
// Expect regathering on all networks and on failed networks to happen once
// respectively in that last 2s with 2s interval.
EXPECT_EQ(1, GetRegatheringReasonCount(
cricket::IceRegatheringReason::OCCASIONAL_REFRESH));
EXPECT_EQ(1, GetRegatheringReasonCount(
cricket::IceRegatheringReason::NETWORK_FAILURE));
SIMULATED_WAIT(false, 11000, clock);
// Expect regathering to happen for another 5 times in 11s with 2s interval.
EXPECT_EQ(6, GetRegatheringReasonCount(
cricket::IceRegatheringReason::OCCASIONAL_REFRESH));
EXPECT_EQ(6, GetRegatheringReasonCount(
cricket::IceRegatheringReason::NETWORK_FAILURE));
}
// Tests that the schedule of ICE regathering on all networks can be started
// when not scheduled initially.
TEST_F(RegatheringControllerTest,
IceRegatheringOnAllNetworksCanBeScheduledAfterStart) {
rtc::ScopedFakeClock clock;
InitializeAndGatherOnceWithSessionCleared();
BasicRegatheringController::Config config(rtc::nullopt, 2000);
regathering_controller()->SetConfig(config);
regathering_controller()->Start();
SIMULATED_WAIT(false, 3000, clock);
// Expect no regathering on all networks.
EXPECT_EQ(0, GetRegatheringReasonCount(
cricket::IceRegatheringReason::OCCASIONAL_REFRESH));
config.regather_on_all_networks_interval_range =
rtc::IntervalRange(2000, 2000);
regathering_controller()->SetConfig(config);
SIMULATED_WAIT(false, 11000, clock);
// Expect regathering to happen for 5 times on all networks in the last 11s
// with 2s interval.
EXPECT_EQ(5, GetRegatheringReasonCount(
cricket::IceRegatheringReason::OCCASIONAL_REFRESH));
}
// Tests that ICE regathering on all networks can be canceled by changing the
// config.
TEST_F(RegatheringControllerTest, IceRegatheringOnAllNetworksCanBeCanceled) {
rtc::ScopedFakeClock clock;
InitializeAndGatherOnceWithSessionCleared();
rtc::IntervalRange regather_all_networks_interval_range(2000, 2000);
BasicRegatheringController::Config config(
regather_all_networks_interval_range, 2000);
regathering_controller()->SetConfig(config);
regathering_controller()->Start();
config.regather_on_all_networks_interval_range.reset();
// Set the regathering interval range on all networks to nullopt should cancel
// the schedule on all networks.
regathering_controller()->SetConfig(config);
SIMULATED_WAIT(false, 10000, clock);
// Expect no regathering on all networks happened in the last 10s.
EXPECT_EQ(0, GetRegatheringReasonCount(
cricket::IceRegatheringReason::OCCASIONAL_REFRESH));
}
// Tests that canceling the regathering on all networks does not cancel the
// schedule on failed networks.
TEST_F(RegatheringControllerTest,
CancelingRegatheringOnAllNetworksDoesNotCancelOnFailedNetworks) {
rtc::ScopedFakeClock clock;
InitializeAndGatherOnceWithSessionCleared();
rtc::IntervalRange regather_all_networks_interval_range(2000, 2000);
BasicRegatheringController::Config config(
regather_all_networks_interval_range, 2000);
regathering_controller()->SetConfig(config);
regathering_controller()->Start();
config.regather_on_all_networks_interval_range =
rtc::IntervalRange(20000, 20000);
// Canceling and rescheduling the regathering on all networks should not
// impact the schedule for failed networks.
regathering_controller()->SetConfig(config);
SIMULATED_WAIT(false, 11000, clock);
// Expect regathering to happen for 5 times for failed networks in the last
// 11s with 2s interval.
EXPECT_EQ(5, GetRegatheringReasonCount(
cricket::IceRegatheringReason::NETWORK_FAILURE));
}
// Tests that canceling the regathering on failed networks does not cancel the
// schedule on all networks.
TEST_F(RegatheringControllerTest,
CancelingRegatheringOnFailedNetworksDoesNotCancelOnAllNetworks) {
rtc::ScopedFakeClock clock;
InitializeAndGatherOnceWithSessionCleared();
rtc::IntervalRange regather_all_networks_interval_range(2000, 2000);
BasicRegatheringController::Config config(
regather_all_networks_interval_range, 2000);
regathering_controller()->SetConfig(config);
regathering_controller()->Start();
config.regather_on_failed_networks_interval = 20000;
// Canceling and rescheduling the regathering on failed networks should not
// impact the schedule for all networks.
regathering_controller()->SetConfig(config);
SIMULATED_WAIT(false, 11000, clock);
// Expect regathering to happen for 5 times for all networks in the last 11s
// with 2s interval.
EXPECT_EQ(5, GetRegatheringReasonCount(
cricket::IceRegatheringReason::OCCASIONAL_REFRESH));
}
// Tests that the schedule of ICE regathering on all networks can be canceled
// and replaced by a new recurring schedule.
TEST_F(RegatheringControllerTest,
ScheduleOfIceRegatheringOnAllNetworksCanBeReplaced) {
rtc::ScopedFakeClock clock;
InitializeAndGatherOnceWithSessionCleared();
rtc::IntervalRange regather_all_networks_interval_range(2000, 2000);
BasicRegatheringController::Config config(
regather_all_networks_interval_range, 2000);
regathering_controller()->SetConfig(config);
regathering_controller()->Start();
config.regather_on_all_networks_interval_range =
rtc::IntervalRange(5000, 5000);
regathering_controller()->SetConfig(config);
SIMULATED_WAIT(false, 3000, clock);
// Expect no regathering from the previous schedule.
EXPECT_EQ(0, GetRegatheringReasonCount(
cricket::IceRegatheringReason::OCCASIONAL_REFRESH));
SIMULATED_WAIT(false, 11000 - 3000, clock);
// Expect regathering to happen twice in the last 11s with 5s interval.
EXPECT_EQ(2, GetRegatheringReasonCount(
cricket::IceRegatheringReason::OCCASIONAL_REFRESH));
}
// Tests that the schedule of ICE regathering on failed networks can be canceled
// and replaced by a new recurring schedule.
TEST_F(RegatheringControllerTest,
ScheduleOfIceRegatheringOnFailedNetworksCanBeReplaced) {
rtc::ScopedFakeClock clock;
InitializeAndGatherOnceWithSessionCleared();
rtc::IntervalRange regather_all_networks_interval_range(2000, 2000);
BasicRegatheringController::Config config(
regather_all_networks_interval_range, 2000);
regathering_controller()->SetConfig(config);
regathering_controller()->Start();
config.regather_on_failed_networks_interval = 5000;
regathering_controller()->SetConfig(config);
SIMULATED_WAIT(false, 3000, clock);
// Expect no regathering from the previous schedule.
EXPECT_EQ(0, GetRegatheringReasonCount(
cricket::IceRegatheringReason::NETWORK_FAILURE));
SIMULATED_WAIT(false, 11000 - 3000, clock);
// Expect regathering to happen twice in the last 11s with 5s interval.
EXPECT_EQ(2, GetRegatheringReasonCount(
cricket::IceRegatheringReason::NETWORK_FAILURE));
}
} // namespace webrtc