Fix potential bug due to malformed input

A reasonable amount of incoming packets could generate feedback
for millions of packets.

Bug: chromium:949020
Change-Id: I7f3e6b75b683af5b2732c472cc92c6788540486b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/131333
Commit-Queue: Johannes Kron <kron@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27481}
diff --git a/call/call.cc b/call/call.cc
index 1e8d3a9..38a4dd5 100644
--- a/call/call.cc
+++ b/call/call.cc
@@ -69,12 +69,12 @@
 namespace webrtc {
 
 namespace {
-bool SendFeedbackOnRequestOnly(const std::vector<RtpExtension>& extensions) {
+bool SendPeriodicFeedback(const std::vector<RtpExtension>& extensions) {
   for (const auto& extension : extensions) {
     if (extension.uri == RtpExtension::kTransportSequenceNumberV2Uri)
-      return true;
+      return false;
   }
-  return false;
+  return true;
 }
 
 // TODO(nisse): This really begs for a shared context struct.
@@ -931,8 +931,8 @@
   TRACE_EVENT0("webrtc", "Call::CreateVideoReceiveStream");
   RTC_DCHECK_CALLED_SEQUENTIALLY(&configuration_sequence_checker_);
 
-  receive_side_cc_.SetSendFeedbackOnRequestOnly(
-      SendFeedbackOnRequestOnly(configuration.rtp.extensions));
+  receive_side_cc_.SetSendPeriodicFeedback(
+      SendPeriodicFeedback(configuration.rtp.extensions));
 
   RegisterRateObserver();
 
diff --git a/modules/congestion_controller/include/receive_side_congestion_controller.h b/modules/congestion_controller/include/receive_side_congestion_controller.h
index 5532b3c..fdf210f 100644
--- a/modules/congestion_controller/include/receive_side_congestion_controller.h
+++ b/modules/congestion_controller/include/receive_side_congestion_controller.h
@@ -38,7 +38,7 @@
                                 size_t payload_size,
                                 const RTPHeader& header);
 
-  void SetSendFeedbackOnRequestOnly(bool send_feedback_on_request_only);
+  void SetSendPeriodicFeedback(bool send_periodic_feedback);
   // TODO(nisse): Delete these methods, design a more specific interface.
   virtual RemoteBitrateEstimator* GetRemoteBitrateEstimator(bool send_side_bwe);
   virtual const RemoteBitrateEstimator* GetRemoteBitrateEstimator(
diff --git a/modules/congestion_controller/receive_side_congestion_controller.cc b/modules/congestion_controller/receive_side_congestion_controller.cc
index 1a95f8c..f886b8e 100644
--- a/modules/congestion_controller/receive_side_congestion_controller.cc
+++ b/modules/congestion_controller/receive_side_congestion_controller.cc
@@ -139,10 +139,9 @@
   }
 }
 
-void ReceiveSideCongestionController::SetSendFeedbackOnRequestOnly(
-    bool send_feedback_on_request_only) {
-  remote_estimator_proxy_.SetSendFeedbackOnRequestOnly(
-      send_feedback_on_request_only);
+void ReceiveSideCongestionController::SetSendPeriodicFeedback(
+    bool send_periodic_feedback) {
+  remote_estimator_proxy_.SetSendPeriodicFeedback(send_periodic_feedback);
 }
 
 RemoteBitrateEstimator*
diff --git a/modules/remote_bitrate_estimator/remote_estimator_proxy.cc b/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
index 009f867..5220d15 100644
--- a/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
+++ b/modules/remote_bitrate_estimator/remote_estimator_proxy.cc
@@ -43,7 +43,7 @@
       media_ssrc_(0),
       feedback_packet_count_(0),
       send_interval_ms_(kDefaultSendIntervalMs),
-      send_feedback_on_request_only_(false) {}
+      send_periodic_feedback_(true) {}
 
 RemoteEstimatorProxy::~RemoteEstimatorProxy() {}
 
@@ -69,7 +69,7 @@
 
 int64_t RemoteEstimatorProxy::TimeUntilNextProcess() {
   rtc::CritScope cs(&lock_);
-  if (send_feedback_on_request_only_) {
+  if (!send_periodic_feedback_) {
     // Wait a day until next process.
     return 24 * 60 * 60 * 1000;
   } else if (last_process_time_ms_ != -1) {
@@ -82,7 +82,7 @@
 
 void RemoteEstimatorProxy::Process() {
   rtc::CritScope cs(&lock_);
-  if (send_feedback_on_request_only_) {
+  if (!send_periodic_feedback_) {
     return;
   }
   last_process_time_ms_ = clock_->TimeInMilliseconds();
@@ -109,10 +109,10 @@
                 rtc::SafeClamp(0.05 * bitrate_bps, kMinTwccRate, kMaxTwccRate));
 }
 
-void RemoteEstimatorProxy::SetSendFeedbackOnRequestOnly(
-    bool send_feedback_on_request_only) {
+void RemoteEstimatorProxy::SetSendPeriodicFeedback(
+    bool send_periodic_feedback) {
   rtc::CritScope cs(&lock_);
-  send_feedback_on_request_only_ = send_feedback_on_request_only;
+  send_periodic_feedback_ = send_periodic_feedback;
 }
 
 void RemoteEstimatorProxy::OnPacketArrival(
@@ -126,12 +126,7 @@
 
   int64_t seq = unwrapper_.Unwrap(sequence_number);
 
-  if (send_feedback_on_request_only_) {
-    // Remove old packet arrival times.
-    auto clear_to_it =
-        packet_arrival_times_.lower_bound(seq - kMaxNumberOfPackets);
-    packet_arrival_times_.erase(packet_arrival_times_.begin(), clear_to_it);
-  } else {
+  if (send_periodic_feedback_) {
     if (periodic_window_start_seq_ &&
         packet_arrival_times_.lower_bound(*periodic_window_start_seq_) ==
             packet_arrival_times_.end()) {
@@ -153,6 +148,20 @@
 
   packet_arrival_times_[seq] = arrival_time;
 
+  // Limit the range of sequence numbers to send feedback for.
+  auto first_arrival_time_to_keep = packet_arrival_times_.lower_bound(
+      packet_arrival_times_.rbegin()->first - kMaxNumberOfPackets);
+  if (first_arrival_time_to_keep != packet_arrival_times_.begin()) {
+    packet_arrival_times_.erase(packet_arrival_times_.begin(),
+                                first_arrival_time_to_keep);
+    if (send_periodic_feedback_) {
+      // |packet_arrival_times_| cannot be empty since we just added one element
+      // and the last element is not deleted.
+      RTC_DCHECK(!packet_arrival_times_.empty());
+      periodic_window_start_seq_ = packet_arrival_times_.begin()->first;
+    }
+  }
+
   if (feedback_request) {
     // Send feedback packet immediately.
     SendFeedbackOnRequest(seq, *feedback_request);
diff --git a/modules/remote_bitrate_estimator/remote_estimator_proxy.h b/modules/remote_bitrate_estimator/remote_estimator_proxy.h
index d13e1a1..fa9f7c8 100644
--- a/modules/remote_bitrate_estimator/remote_estimator_proxy.h
+++ b/modules/remote_bitrate_estimator/remote_estimator_proxy.h
@@ -51,7 +51,7 @@
   int64_t TimeUntilNextProcess() override;
   void Process() override;
   void OnBitrateChanged(int bitrate);
-  void SetSendFeedbackOnRequestOnly(bool send_feedback_on_request_only);
+  void SetSendPeriodicFeedback(bool send_periodic_feedback);
 
  private:
   static const int kMaxNumberOfPackets;
@@ -86,7 +86,7 @@
   // Map unwrapped seq -> time.
   std::map<int64_t, int64_t> packet_arrival_times_ RTC_GUARDED_BY(&lock_);
   int64_t send_interval_ms_ RTC_GUARDED_BY(&lock_);
-  bool send_feedback_on_request_only_ RTC_GUARDED_BY(&lock_);
+  bool send_periodic_feedback_ RTC_GUARDED_BY(&lock_);
 };
 
 }  // namespace webrtc
diff --git a/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc b/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc
index ab20d5a..e66b9c9 100644
--- a/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc
+++ b/modules/remote_bitrate_estimator/remote_estimator_proxy_unittest.cc
@@ -215,6 +215,60 @@
   Process();
 }
 
+TEST_F(RemoteEstimatorProxyTest, HandlesMalformedSequenceNumbers) {
+  // This test generates incoming packets with large jumps in sequence numbers.
+  // When unwrapped, the sequeunce numbers of these 30 incoming packets, will
+  // span a range of roughly 650k packets. Test that we only send feedback for
+  // the last packets. Test for regression found in chromium:949020.
+  const int64_t kDeltaMs = 1000;
+  for (int i = 0; i < 10; ++i) {
+    IncomingPacket(kBaseSeq + i, kBaseTimeMs + 3 * i * kDeltaMs);
+    IncomingPacket(kBaseSeq + 20000 + i, kBaseTimeMs + (3 * i + 1) * kDeltaMs);
+    IncomingPacket(kBaseSeq + 40000 + i, kBaseTimeMs + (3 * i + 2) * kDeltaMs);
+  }
+
+  // Only expect feedback for the last two packets.
+  EXPECT_CALL(router_, SendTransportFeedback(_))
+      .WillOnce(Invoke([&](rtcp::TransportFeedback* feedback_packet) {
+        EXPECT_EQ(kBaseSeq + 20000 + 9, feedback_packet->GetBaseSequence());
+        EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc());
+        EXPECT_THAT(SequenceNumbers(*feedback_packet),
+                    ElementsAre(kBaseSeq + 20009, kBaseSeq + 40009));
+        EXPECT_THAT(TimestampsMs(*feedback_packet),
+                    ElementsAre(kBaseTimeMs + 28 * kDeltaMs,
+                                kBaseTimeMs + 29 * kDeltaMs));
+        return true;
+      }));
+
+  Process();
+}
+
+TEST_F(RemoteEstimatorProxyTest, HandlesBackwardsWrappingSequenceNumbers) {
+  // This test is like HandlesMalformedSequenceNumbers but for negative wrap
+  // arounds. Test that we only send feedback for the packets with highest
+  // sequence numbers.  Test for regression found in chromium:949020.
+  const int64_t kDeltaMs = 1000;
+  for (int i = 0; i < 10; ++i) {
+    IncomingPacket(kBaseSeq + i, kBaseTimeMs + 3 * i * kDeltaMs);
+    IncomingPacket(kBaseSeq + 40000 + i, kBaseTimeMs + (3 * i + 1) * kDeltaMs);
+    IncomingPacket(kBaseSeq + 20000 + i, kBaseTimeMs + (3 * i + 2) * kDeltaMs);
+  }
+
+  // Only expect feedback for the first two packets.
+  EXPECT_CALL(router_, SendTransportFeedback(_))
+      .WillOnce(Invoke([&](rtcp::TransportFeedback* feedback_packet) {
+        EXPECT_EQ(kBaseSeq + 40000, feedback_packet->GetBaseSequence());
+        EXPECT_EQ(kMediaSsrc, feedback_packet->media_ssrc());
+        EXPECT_THAT(SequenceNumbers(*feedback_packet),
+                    ElementsAre(kBaseSeq + 40000, kBaseSeq));
+        EXPECT_THAT(TimestampsMs(*feedback_packet),
+                    ElementsAre(kBaseTimeMs + kDeltaMs, kBaseTimeMs));
+        return true;
+      }));
+
+  Process();
+}
+
 TEST_F(RemoteEstimatorProxyTest, ResendsTimestampsOnReordering) {
   IncomingPacket(kBaseSeq, kBaseTimeMs);
   IncomingPacket(kBaseSeq + 2, kBaseTimeMs + 2);
@@ -348,19 +402,19 @@
 //////////////////////////////////////////////////////////////////////////////
 typedef RemoteEstimatorProxyTest RemoteEstimatorProxyOnRequestTest;
 TEST_F(RemoteEstimatorProxyOnRequestTest, TimeUntilNextProcessIsHigh) {
-  proxy_.SetSendFeedbackOnRequestOnly(true);
+  proxy_.SetSendPeriodicFeedback(false);
   EXPECT_GE(proxy_.TimeUntilNextProcess(), 60 * 60 * 1000);
 }
 
 TEST_F(RemoteEstimatorProxyOnRequestTest, ProcessDoesNotSendFeedback) {
-  proxy_.SetSendFeedbackOnRequestOnly(true);
+  proxy_.SetSendPeriodicFeedback(false);
   IncomingPacket(kBaseSeq, kBaseTimeMs);
   EXPECT_CALL(router_, SendTransportFeedback(_)).Times(0);
   Process();
 }
 
 TEST_F(RemoteEstimatorProxyOnRequestTest, RequestSinglePacketFeedback) {
-  proxy_.SetSendFeedbackOnRequestOnly(true);
+  proxy_.SetSendPeriodicFeedback(false);
   IncomingPacket(kBaseSeq, kBaseTimeMs);
   IncomingPacket(kBaseSeq + 1, kBaseTimeMs + kMaxSmallDeltaMs);
   IncomingPacket(kBaseSeq + 2, kBaseTimeMs + 2 * kMaxSmallDeltaMs);
@@ -384,7 +438,7 @@
 }
 
 TEST_F(RemoteEstimatorProxyOnRequestTest, RequestLastFivePacketFeedback) {
-  proxy_.SetSendFeedbackOnRequestOnly(true);
+  proxy_.SetSendPeriodicFeedback(false);
   int i = 0;
   for (; i < 10; ++i) {
     IncomingPacket(kBaseSeq + i, kBaseTimeMs + i * kMaxSmallDeltaMs);
@@ -415,7 +469,7 @@
 
 TEST_F(RemoteEstimatorProxyOnRequestTest,
        RequestLastFivePacketFeedbackMissingPackets) {
-  proxy_.SetSendFeedbackOnRequestOnly(true);
+  proxy_.SetSendPeriodicFeedback(false);
   int i = 0;
   for (; i < 10; ++i) {
     if (i != 7 && i != 9)