Replace BasicRegatheringController with RepeatingTaskHandle

The `BasicRegatheringController` class was essentially a thin wrapper
around a recurring task. This change removes the separate class and
implements the regathering logic directly in `P2PTransportChannel` using
`webrtc::RepeatingTaskHandle` which also avoids storing a pointer to the
PortAllocatorSession outside of P2PTransportChannel.

This simplifies the code by removing an extra layer of abstraction and
reducing boilerplate.

Key changes:
* Deleted `p2p/base/regathering_controller.{h,cc}` and the unit tests
  file.
* Migrated the tests `p2p/base/p2p_transport_channel_unittest.cc` to
  ensure continued coverage of regathering scheduling and intervals.
* Updated `P2PTransportChannel` to manage the recurring regathering
  task directly using `RepeatingTaskHandle`.

This will help allow initial construction of P2PTransportChannel on the
signaling thread in the future even though ownership and logic will
continue to run on the network thread. This also retains state within
the class, avoiding having more classes pointing to the same state.

Bug: none
Change-Id: I019f573cb3e6a52f1b46e01610a748f1691aacab
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/427681
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Commit-Queue: Tomas Gunnarsson <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#46282}
diff --git a/p2p/BUILD.gn b/p2p/BUILD.gn
index 2e918a5..6ff122b 100644
--- a/p2p/BUILD.gn
+++ b/p2p/BUILD.gn
@@ -491,7 +491,6 @@
     ":port",
     ":port_allocator",
     ":port_interface",
-    ":regathering_controller",
     ":stun_dictionary",
     ":transport_description",
     ":wrapping_active_ice_controller",
@@ -534,6 +533,7 @@
     "../rtc_base/network:received_packet",
     "../rtc_base/network:sent_packet",
     "../rtc_base/system:rtc_export",
+    "../rtc_base/task_utils:repeating_task",
     "../system_wrappers:metrics",
     "//third_party/abseil-cpp/absl/algorithm:container",
     "//third_party/abseil-cpp/absl/base:core_headers",
@@ -675,26 +675,6 @@
   ]
 }
 
-rtc_library("regathering_controller") {
-  sources = [
-    "base/regathering_controller.cc",
-    "base/regathering_controller.h",
-  ]
-  deps = [
-    ":connection",
-    ":ice_transport_internal",
-    ":p2p_constants",
-    ":packet_transport_internal",
-    ":port_allocator",
-    "../api:sequence_checker",
-    "../api/task_queue",
-    "../api/task_queue:pending_task_safety_flag",
-    "../api/units:time_delta",
-    "../rtc_base:checks",
-    "../rtc_base:network_route",
-  ]
-}
-
 rtc_library("stun_dictionary") {
   sources = [
     "base/stun_dictionary.cc",
@@ -1188,7 +1168,6 @@
       "base/packet_transport_internal_unittest.cc",
       "base/port_allocator_unittest.cc",
       "base/port_unittest.cc",
-      "base/regathering_controller_unittest.cc",
       "base/stun_dictionary_unittest.cc",
       "base/stun_port_unittest.cc",
       "base/stun_request_unittest.cc",
@@ -1234,7 +1213,6 @@
       ":port",
       ":port_allocator",
       ":port_interface",
-      ":regathering_controller",
       ":relay_port_factory_interface",
       ":stun_dictionary",
       ":stun_port",
diff --git a/p2p/base/p2p_transport_channel.cc b/p2p/base/p2p_transport_channel.cc
index ceddcd2..3ee1f25 100644
--- a/p2p/base/p2p_transport_channel.cc
+++ b/p2p/base/p2p_transport_channel.cc
@@ -38,6 +38,7 @@
 #include "api/local_network_access_permission.h"
 #include "api/rtc_error.h"
 #include "api/sequence_checker.h"
+#include "api/task_queue/task_queue_base.h"
 #include "api/transport/enums.h"
 #include "api/transport/stun.h"
 #include "api/units/time_delta.h"
@@ -55,7 +56,6 @@
 #include "p2p/base/port.h"
 #include "p2p/base/port_allocator.h"
 #include "p2p/base/port_interface.h"
-#include "p2p/base/regathering_controller.h"
 #include "p2p/base/transport_description.h"
 #include "p2p/base/wrapping_active_ice_controller.h"
 #include "p2p/dtls/dtls_stun_piggyback_callbacks.h"
@@ -74,6 +74,7 @@
 #include "rtc_base/network_route.h"
 #include "rtc_base/socket.h"
 #include "rtc_base/socket_address.h"
+#include "rtc_base/task_utils/repeating_task.h"
 #include "rtc_base/thread.h"
 #include "rtc_base/trace_event.h"
 #include "system_wrappers/include/metrics.h"
@@ -201,11 +202,6 @@
   // Validate IceConfig even for mostly built-in constant default values in case
   // we change them.
   RTC_DCHECK(config_.IsValid().ok());
-  BasicRegatheringController::Config regathering_config;
-  regathering_config.regather_on_failed_networks_interval =
-      config_.regather_on_failed_networks_interval_or_default().ms();
-  regathering_controller_ = std::make_unique<BasicRegatheringController>(
-      regathering_config, this, network_thread_);
   // We populate the change in the candidate filter to the session taken by
   // the transport.
   allocator_->SubscribeCandidateFilterChanged(
@@ -242,6 +238,7 @@
 P2PTransportChannel::~P2PTransportChannel() {
   TRACE_EVENT0("webrtc", "P2PTransportChannel::~P2PTransportChannel");
   RTC_DCHECK_RUN_ON(network_thread_);
+  regathering_task_handle_.Stop();
   std::vector<Connection*> copy(connections_.begin(), connections_.end());
   for (Connection* connection : copy) {
     connection->UnsubscribeDestroyed(this);
@@ -292,7 +289,6 @@
     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
@@ -629,6 +625,9 @@
     RTC_LOG(LS_INFO)
         << "Set regather_on_failed_networks_interval to "
         << config_.regather_on_failed_networks_interval_or_default();
+    if (regathering_task_handle_.Running()) {
+      OnStartedPinging();  // Restart the regathering timer.
+    }
   }
 
   if (config_.receiving_switching_delay != config.receiving_switching_delay) {
@@ -715,11 +714,6 @@
                      << config.stun_keepalive_interval_or_default();
   }
 
-  BasicRegatheringController::Config regathering_config;
-  regathering_config.regather_on_failed_networks_interval =
-      config_.regather_on_failed_networks_interval_or_default().ms();
-  regathering_controller_->SetConfig(regathering_config);
-
   config_.vpn_preference = config.vpn_preference;
   allocator_->SetVpnPreference(config_.vpn_preference);
 
@@ -1758,7 +1752,20 @@
   RTC_LOG(LS_INFO) << ToString()
                    << ": Have a pingable connection for the first time; "
                       "starting to ping.";
-  regathering_controller_->Start();
+  regathering_task_handle_.Stop();
+  regathering_task_handle_ = RepeatingTaskHandle::DelayedStart(
+      TaskQueueBase::Current(),
+      config_.regather_on_failed_networks_interval_or_default(), [this]() {
+        RTC_DCHECK_RUN_ON(network_thread_);
+        if (allocator_session() && allocator_session()->IsCleared()) {
+          // 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.
+          allocator_session()->RegatherOnFailedNetworks();
+        }
+        return config_.regather_on_failed_networks_interval_or_default();
+      });
 }
 
 bool P2PTransportChannel::IsPortPruned(const PortInterface* port) const {
diff --git a/p2p/base/p2p_transport_channel.h b/p2p/base/p2p_transport_channel.h
index 1660541..7d0ea26 100644
--- a/p2p/base/p2p_transport_channel.h
+++ b/p2p/base/p2p_transport_channel.h
@@ -58,7 +58,6 @@
 #include "p2p/base/port.h"
 #include "p2p/base/port_allocator.h"
 #include "p2p/base/port_interface.h"
-#include "p2p/base/regathering_controller.h"
 #include "p2p/base/stun_dictionary.h"
 #include "p2p/base/transport_description.h"
 #include "p2p/dtls/dtls_stun_piggyback_callbacks.h"
@@ -73,6 +72,7 @@
 #include "rtc_base/socket_address.h"
 #include "rtc_base/strings/string_builder.h"
 #include "rtc_base/system/rtc_export.h"
+#include "rtc_base/task_utils/repeating_task.h"
 #include "rtc_base/thread_annotations.h"
 
 namespace webrtc {
@@ -473,8 +473,7 @@
   IceMode remote_ice_mode_ RTC_GUARDED_BY(network_thread_);
   IceRole ice_role_ RTC_GUARDED_BY(network_thread_);
   IceGatheringState gathering_state_ RTC_GUARDED_BY(network_thread_);
-  std::unique_ptr<BasicRegatheringController> regathering_controller_
-      RTC_GUARDED_BY(network_thread_);
+  RepeatingTaskHandle regathering_task_handle_ RTC_GUARDED_BY(network_thread_);
   Timestamp last_ping_sent_ RTC_GUARDED_BY(network_thread_) = Timestamp::Zero();
   int weak_ping_interval_ RTC_GUARDED_BY(network_thread_) =
       kWeakPingInterval.ms();
diff --git a/p2p/base/p2p_transport_channel_unittest.cc b/p2p/base/p2p_transport_channel_unittest.cc
index de2a51f..b9d3a55 100644
--- a/p2p/base/p2p_transport_channel_unittest.cc
+++ b/p2p/base/p2p_transport_channel_unittest.cc
@@ -7155,5 +7155,117 @@
   Run(true, true);
 }
 
+class P2PTransportChannelRegatheringTest : public P2PTransportChannelPingTest {
+ public:
+  void SetupChannel(IceConfig config) {
+    // Use a fixed environment for the allocator and channel.
+    env_ = std::make_unique<Environment>(CreateEnvironment());
+    allocator_ = std::make_unique<FakePortAllocator>(*env_, ss());
+    channel_ = std::make_unique<P2PTransportChannel>(*env_, "regather", 1,
+                                                     allocator_.get());
+    PrepareChannel(channel_.get());
+    channel_->SetIceConfig(config);
+    channel_->SetIceRole(ICEROLE_CONTROLLING);
+    channel_->SetIceParameters(kIceParams[0]);
+    channel_->SetRemoteIceParameters(kIceParams[1]);
+    channel_->MaybeStartGathering();
+
+    // Create a connection to trigger pinging which starts the regathering
+    // timer. We need to make sure the connection is pingable.
+    channel_->AddRemoteCandidate(
+        CreateUdpCandidate(IceCandidateType::kHost, "1.1.1.1", 1, 1));
+    connection_ = WaitForConnectionTo(channel_.get(), "1.1.1.1", 1);
+    EXPECT_TRUE(connection_ != nullptr);
+
+    channel_->allocator_session()->SubscribeIceRegathering(
+        [this](PortAllocatorSession*, IceRegatheringReason reason) {
+          regathering_counts_[reason]++;
+        });
+  }
+
+  int GetRegatheringCount(IceRegatheringReason reason) {
+    return regathering_counts_[reason];
+  }
+
+  std::unique_ptr<Environment> env_;
+  std::unique_ptr<FakePortAllocator> allocator_;
+  std::unique_ptr<P2PTransportChannel> channel_;
+  Connection* connection_ = nullptr;
+  std::map<IceRegatheringReason, int> regathering_counts_;
+};
+
+TEST_F(P2PTransportChannelRegatheringTest,
+       IceRegatheringDoesNotOccurIfSessionNotCleared) {
+  ScopedFakeClock clock;
+  IceConfig config;
+  config.regather_on_failed_networks_interval = TimeDelta::Millis(2000);
+  SetupChannel(config);
+
+  // Session is not cleared by default.
+  // Expect no regathering in the last 10s.
+  // We use WaitUntil with a condition that is always false to wait for timeout,
+  // but we expect it to fail (return false).
+  EXPECT_FALSE(WaitUntil([&] { return false; },
+                         {.timeout = TimeDelta::Seconds(10), .clock = &clock}));
+  EXPECT_EQ(0, GetRegatheringCount(IceRegatheringReason::NETWORK_FAILURE));
+}
+
+TEST_F(P2PTransportChannelRegatheringTest, IceRegatheringRepeatsAsScheduled) {
+  ScopedFakeClock clock;
+  IceConfig config;
+  config.regather_on_failed_networks_interval = TimeDelta::Millis(2000);
+  SetupChannel(config);
+
+  channel_->allocator_session()->ClearGettingPorts();
+
+  // Expect no regathering immediately (wait < 2000ms).
+  EXPECT_FALSE(
+      WaitUntil([&] { return false; },
+                {.timeout = TimeDelta::Millis(1900), .clock = &clock}));
+  EXPECT_EQ(0, GetRegatheringCount(IceRegatheringReason::NETWORK_FAILURE));
+
+  // Expect regathering to happen once after 2s.
+  EXPECT_TRUE(WaitUntil(
+      [&] {
+        return GetRegatheringCount(IceRegatheringReason::NETWORK_FAILURE) == 1;
+      },
+      {.timeout = TimeDelta::Millis(500), .clock = &clock}));
+
+  // Expect regathering to happen for another 5 times in 11s with 2s interval.
+  // Total 6.
+  EXPECT_TRUE(WaitUntil(
+      [&] {
+        return GetRegatheringCount(IceRegatheringReason::NETWORK_FAILURE) == 6;
+      },
+      {.timeout = TimeDelta::Seconds(11), .clock = &clock}));
+}
+
+TEST_F(P2PTransportChannelRegatheringTest,
+       ScheduleOfIceRegatheringOnFailedNetworksCanBeReplaced) {
+  ScopedFakeClock clock;
+  IceConfig config;
+  config.regather_on_failed_networks_interval = TimeDelta::Millis(2000);
+  SetupChannel(config);
+
+  channel_->allocator_session()->ClearGettingPorts();
+
+  config.regather_on_failed_networks_interval = TimeDelta::Millis(5000);
+  channel_->SetIceConfig(config);
+
+  // Expect no regathering from the previous schedule (Wait 3s, previous was
+  // 2s). Since we reset the schedule, it should restart counting 5s from now.
+  EXPECT_FALSE(WaitUntil([&] { return false; },
+                         {.timeout = TimeDelta::Seconds(3), .clock = &clock}));
+  EXPECT_EQ(0, GetRegatheringCount(IceRegatheringReason::NETWORK_FAILURE));
+
+  // Expect regathering to happen twice in the last 11s (total 14s) with 5s
+  // interval. First at 5s, second at 10s.
+  EXPECT_TRUE(WaitUntil(
+      [&] {
+        return GetRegatheringCount(IceRegatheringReason::NETWORK_FAILURE) == 2;
+      },
+      {.timeout = TimeDelta::Seconds(8), .clock = &clock}));
+}
+
 }  // namespace
 }  // namespace webrtc
diff --git a/p2p/base/regathering_controller.cc b/p2p/base/regathering_controller.cc
deleted file mode 100644
index 406d3c8..0000000
--- a/p2p/base/regathering_controller.cc
+++ /dev/null
@@ -1,96 +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/regathering_controller.h"
-
-#include <optional>
-
-#include "api/sequence_checker.h"
-#include "api/task_queue/pending_task_safety_flag.h"
-#include "api/task_queue/task_queue_base.h"
-#include "api/units/time_delta.h"
-#include "p2p/base/ice_transport_internal.h"
-#include "p2p/base/packet_transport_internal.h"
-#include "rtc_base/checks.h"
-#include "rtc_base/network_route.h"
-
-namespace webrtc {
-
-BasicRegatheringController::BasicRegatheringController(
-    const Config& config,
-    IceTransportInternal* ice_transport,
-    TaskQueueBase* thread)
-    : config_(config), ice_transport_(ice_transport), thread_(thread) {
-  RTC_DCHECK(thread_);
-  RTC_DCHECK_RUN_ON(thread_);
-  RTC_DCHECK(ice_transport_);
-  ice_transport_->SubscribeIceTransportStateChanged(
-      [this](IceTransportInternal* transport) {
-        OnIceTransportStateChanged(transport);
-      });
-  ice_transport->SubscribeWritableState(
-      this, [this](PacketTransportInternal* transport) {
-        OnIceTransportWritableState(transport);
-      });
-  ice_transport->SubscribeReceivingState(
-      [this](PacketTransportInternal* transport) {
-        OnIceTransportReceivingState(transport);
-      });
-  ice_transport->SubscribeNetworkRouteChanged(
-      this, [this](std::optional<NetworkRoute> network_route) {
-        OnIceTransportNetworkRouteChanged(network_route);
-      });
-}
-
-BasicRegatheringController::~BasicRegatheringController() {
-  RTC_DCHECK_RUN_ON(thread_);
-}
-
-void BasicRegatheringController::Start() {
-  RTC_DCHECK_RUN_ON(thread_);
-  ScheduleRecurringRegatheringOnFailedNetworks();
-}
-
-void BasicRegatheringController::SetConfig(const Config& config) {
-  RTC_DCHECK_RUN_ON(thread_);
-  bool need_reschedule_on_failed_networks =
-      pending_regathering_ && (config_.regather_on_failed_networks_interval !=
-                               config.regather_on_failed_networks_interval);
-  config_ = config;
-  if (need_reschedule_on_failed_networks) {
-    ScheduleRecurringRegatheringOnFailedNetworks();
-  }
-}
-
-void BasicRegatheringController::
-    ScheduleRecurringRegatheringOnFailedNetworks() {
-  RTC_DCHECK_RUN_ON(thread_);
-  RTC_DCHECK(config_.regather_on_failed_networks_interval >= 0);
-  // Reset pending_regathering_ to cancel any potentially pending tasks.
-  pending_regathering_.reset(new ScopedTaskSafety());
-
-  thread_->PostDelayedTask(
-      SafeTask(pending_regathering_->flag(),
-               [this]() {
-                 RTC_DCHECK_RUN_ON(thread_);
-                 // 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();
-                 }
-                 ScheduleRecurringRegatheringOnFailedNetworks();
-               }),
-      TimeDelta::Millis(config_.regather_on_failed_networks_interval));
-}
-
-}  // namespace webrtc
diff --git a/p2p/base/regathering_controller.h b/p2p/base/regathering_controller.h
deleted file mode 100644
index 144c3c6..0000000
--- a/p2p/base/regathering_controller.h
+++ /dev/null
@@ -1,101 +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_REGATHERING_CONTROLLER_H_
-#define P2P_BASE_REGATHERING_CONTROLLER_H_
-
-#include <memory>
-#include <optional>
-
-#include "api/task_queue/pending_task_safety_flag.h"
-#include "api/task_queue/task_queue_base.h"
-#include "p2p/base/ice_transport_internal.h"
-#include "p2p/base/p2p_constants.h"
-#include "p2p/base/packet_transport_internal.h"
-#include "p2p/base/port_allocator.h"
-#include "rtc_base/network_route.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 RegatherOnFailedNetworks on the PortAllocatorSession when
-// regathering is desired.
-//
-// "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:
-  struct Config {
-    int regather_on_failed_networks_interval =
-        kRegatherOnFailedNetworksInterval.ms();
-  };
-
-  BasicRegatheringController() = delete;
-  BasicRegatheringController(const Config& config,
-                             IceTransportInternal* ice_transport,
-                             TaskQueueBase* thread);
-  virtual ~BasicRegatheringController();
-  // 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(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(IceTransportInternal*) {}
-  void OnIceTransportWritableState(PacketTransportInternal*) {}
-  void OnIceTransportReceivingState(PacketTransportInternal*) {}
-  void OnIceTransportNetworkRouteChanged(std::optional<NetworkRoute>) {}
-  // 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();
-
-  // We use a flag to be able to cancel pending regathering operations when
-  // the object goes out of scope or the config changes.
-  std::unique_ptr<ScopedTaskSafety> pending_regathering_;
-  Config config_;
-  IceTransportInternal* ice_transport_;
-  PortAllocatorSession* allocator_session_ = nullptr;
-  TaskQueueBase* const thread_;
-};
-
-}  // namespace webrtc
-
-#endif  // P2P_BASE_REGATHERING_CONTROLLER_H_
diff --git a/p2p/base/regathering_controller_unittest.cc b/p2p/base/regathering_controller_unittest.cc
deleted file mode 100644
index 3243086..0000000
--- a/p2p/base/regathering_controller_unittest.cc
+++ /dev/null
@@ -1,188 +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/regathering_controller.h"
-
-#include <map>
-#include <memory>
-#include <vector>
-
-#include "api/environment/environment_factory.h"
-#include "api/transport/enums.h"
-#include "p2p/base/ice_transport_internal.h"
-#include "p2p/base/p2p_constants.h"
-#include "p2p/base/port.h"
-#include "p2p/base/port_allocator.h"
-#include "p2p/base/port_interface.h"
-#include "p2p/test/fake_port_allocator.h"
-#include "p2p/test/mock_ice_transport.h"
-#include "p2p/test/stun_server.h"
-#include "rtc_base/fake_clock.h"
-#include "rtc_base/gunit.h"
-#include "rtc_base/socket_address.h"
-#include "rtc_base/third_party/sigslot/sigslot.h"
-#include "rtc_base/thread.h"
-#include "rtc_base/virtual_socket_server.h"
-#include "test/gtest.h"
-
-namespace {
-
-constexpr int kOnlyLocalPorts = webrtc::PORTALLOCATOR_DISABLE_STUN |
-                                webrtc::PORTALLOCATOR_DISABLE_RELAY |
-                                webrtc::PORTALLOCATOR_DISABLE_TCP;
-// The address of the public STUN server.
-const webrtc::SocketAddress kStunAddr("99.99.99.1", webrtc::STUN_SERVER_PORT);
-// The addresses for the public TURN server.
-const webrtc::SocketAddress kTurnUdpIntAddr("99.99.99.3",
-                                            webrtc::STUN_SERVER_PORT);
-const webrtc::RelayCredentials kRelayCredentials("test", "test");
-constexpr char kIceUfrag[] = "UF00";
-constexpr char kIcePwd[] = "TESTICEPWD00000000000000";
-
-}  // namespace
-
-namespace webrtc {
-
-class RegatheringControllerTest : public ::testing::Test,
-                                  public sigslot::has_slots<> {
- public:
-  RegatheringControllerTest()
-      : vss_(std::make_unique<VirtualSocketServer>()),
-        thread_(vss_.get()),
-        ice_transport_(std::make_unique<MockIceTransport>()),
-        allocator_(std::make_unique<FakePortAllocator>(CreateEnvironment(),
-                                                       vss_.get())) {
-    BasicRegatheringController::Config regathering_config;
-    regathering_config.regather_on_failed_networks_interval = 0;
-    regathering_controller_.reset(new BasicRegatheringController(
-        regathering_config, ice_transport_.get(), Thread::Current()));
-  }
-
-  // Initializes the allocator and gathers candidates once by StartGettingPorts.
-  void InitializeAndGatherOnce() {
-    ServerAddresses stun_servers;
-    stun_servers.insert(kStunAddr);
-    RelayServerConfig turn_server;
-    turn_server.credentials = kRelayCredentials;
-    turn_server.ports.push_back(ProtocolAddress(kTurnUdpIntAddr, PROTO_UDP));
-    std::vector<RelayServerConfig> turn_servers(1, turn_server);
-    allocator_->set_flags(kOnlyLocalPorts);
-    allocator_->SetConfiguration(stun_servers, turn_servers, 0 /* pool size */,
-                                 NO_PRUNE);
-    allocator_session_ = allocator_->CreateSession(
-        "test", 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_->SubscribeIceRegathering(
-        [this](PortAllocatorSession* allocator_session,
-               IceRegatheringReason reason) {
-          OnIceRegathering(allocator_session, reason);
-        });
-    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(PortAllocatorSession* /* allocator_session */,
-                        IceRegatheringReason reason) {
-    ++count_[reason];
-  }
-
-  int GetRegatheringReasonCount(IceRegatheringReason reason) {
-    return count_[reason];
-  }
-
-  BasicRegatheringController* regathering_controller() {
-    return regathering_controller_.get();
-  }
-
- private:
-  std::unique_ptr<VirtualSocketServer> vss_;
-  AutoSocketServerThread thread_;
-  std::unique_ptr<IceTransportInternal> ice_transport_;
-  std::unique_ptr<BasicRegatheringController> regathering_controller_;
-  std::unique_ptr<PortAllocator> allocator_;
-  std::unique_ptr<PortAllocatorSession> allocator_session_;
-  std::map<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) {
-  ScopedFakeClock clock;
-  InitializeAndGatherOnce();  // Session not cleared.
-
-  BasicRegatheringController::Config config;
-  config.regather_on_failed_networks_interval = 2000;
-  regathering_controller()->SetConfig(config);
-  regathering_controller()->Start();
-  SIMULATED_WAIT(false, 10000, clock);
-  // Expect no regathering in the last 10s.
-  EXPECT_EQ(0,
-            GetRegatheringReasonCount(IceRegatheringReason::NETWORK_FAILURE));
-}
-
-TEST_F(RegatheringControllerTest, IceRegatheringRepeatsAsScheduled) {
-  ScopedFakeClock clock;
-  InitializeAndGatherOnceWithSessionCleared();
-
-  BasicRegatheringController::Config config;
-  config.regather_on_failed_networks_interval = 2000;
-  regathering_controller()->SetConfig(config);
-  regathering_controller()->Start();
-  SIMULATED_WAIT(false, 2000 - 1, clock);
-  // Expect no regathering.
-  EXPECT_EQ(0,
-            GetRegatheringReasonCount(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(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(IceRegatheringReason::NETWORK_FAILURE));
-}
-
-// Tests that the schedule of ICE regathering on failed networks can be canceled
-// and replaced by a new recurring schedule.
-TEST_F(RegatheringControllerTest,
-       ScheduleOfIceRegatheringOnFailedNetworksCanBeReplaced) {
-  ScopedFakeClock clock;
-  InitializeAndGatherOnceWithSessionCleared();
-
-  BasicRegatheringController::Config config;
-  config.regather_on_failed_networks_interval = 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(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(IceRegatheringReason::NETWORK_FAILURE));
-}
-
-}  // namespace webrtc