dcsctp: Add Data Tracker

The Data Tracker's purpose is to keep track of all received DATA chunks
and to ACK/NACK that data, by generating SACK chunks reflecting its view
of what has been received and what has been lost.

It also contains logic for _when_ to send the SACKs, as that's different
depending on e.g. packet loss. Generally, SACKs are sent every second
packet on a connection with no packet loss, and can also be sent on a
delayed timer.

In case partial reliability is used, and the transmitter has decided
that some data shouldn't be retransmitted, it will send a FORWARD-TSN
chunk, which this class also handles, by "forgetting" about those
chunks.

Bug: webrtc:12614
Change-Id: Ifafb0c211f6a47872e81830165ab5fc43ee7f366
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/213664
Commit-Queue: Victor Boivie <boivie@webrtc.org>
Reviewed-by: Tommi <tommi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33676}
diff --git a/net/dcsctp/rx/data_tracker.h b/net/dcsctp/rx/data_tracker.h
new file mode 100644
index 0000000..a528967
--- /dev/null
+++ b/net/dcsctp/rx/data_tracker.h
@@ -0,0 +1,121 @@
+/*
+ *  Copyright (c) 2021 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 NET_DCSCTP_RX_DATA_TRACKER_H_
+#define NET_DCSCTP_RX_DATA_TRACKER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <cstdint>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "net/dcsctp/common/sequence_numbers.h"
+#include "net/dcsctp/packet/chunk/data_common.h"
+#include "net/dcsctp/packet/chunk/sack_chunk.h"
+#include "net/dcsctp/packet/data.h"
+#include "net/dcsctp/timer/timer.h"
+
+namespace dcsctp {
+
+// Keeps track of received DATA chunks and handles all logic for _when_ to
+// create SACKs and also _how_ to generate them.
+//
+// It only uses TSNs to track delivery and doesn't need to be aware of streams.
+//
+// SACKs are optimally sent every second packet on connections with no packet
+// loss. When packet loss is detected, it's sent for every packet. When SACKs
+// are not sent directly, a timer is used to send a SACK delayed (by RTO/2, or
+// 200ms, whatever is smallest).
+class DataTracker {
+ public:
+  explicit DataTracker(absl::string_view log_prefix,
+                       Timer* delayed_ack_timer,
+                       TSN peer_initial_tsn)
+      : log_prefix_(std::string(log_prefix) + "dtrack: "),
+        delayed_ack_timer_(*delayed_ack_timer),
+        last_cumulative_acked_tsn_(
+            tsn_unwrapper_.Unwrap(TSN(*peer_initial_tsn - 1))) {}
+
+  // Call for every incoming data chunk.
+  void Observe(TSN tsn,
+               AnyDataChunk::ImmediateAckFlag immediate_ack =
+                   AnyDataChunk::ImmediateAckFlag(false));
+  // Called at the end of processing an SCTP packet.
+  void ObservePacketEnd();
+
+  // Called for incoming FORWARD-TSN/I-FORWARD-TSN chunks
+  void HandleForwardTsn(TSN new_cumulative_ack);
+
+  // Indicates if a SACK should be sent. There may be other reasons to send a
+  // SACK, but if this function indicates so, it should be sent as soon as
+  // possible. Calling this function will make it clear a flag so that if it's
+  // called again, it will probably return false.
+  //
+  // If the delayed ack timer is running, this method will return false _unless_
+  // `also_if_delayed` is set to true. Then it will return true as well.
+  bool ShouldSendAck(bool also_if_delayed = false);
+
+  // Returns the last cumulative ack TSN - the last seen data chunk's TSN
+  // value before any packet loss was detected.
+  TSN last_cumulative_acked_tsn() const {
+    return TSN(last_cumulative_acked_tsn_.Wrap());
+  }
+
+  // Returns true if the received `tsn` would increase the cumulative ack TSN.
+  bool will_increase_cum_ack_tsn(TSN tsn) const;
+
+  // Forces `ShouldSendSack` to return true.
+  void ForceImmediateSack();
+
+  // Note that this will clear `duplicates_`, so every SackChunk that is
+  // consumed must be sent.
+  SackChunk CreateSelectiveAck(size_t a_rwnd);
+
+  void HandleDelayedAckTimerExpiry();
+
+ private:
+  enum class AckState {
+    // No need to send an ACK.
+    kIdle,
+
+    // Has received data chunks (but not yet end of packet).
+    kBecomingDelayed,
+
+    // Has received data chunks and the end of a packet. Delayed ack timer is
+    // running and a SACK will be sent on expiry, or if DATA is sent, or after
+    // next packet with data.
+    kDelayed,
+
+    // Send a SACK immediately after handling this packet.
+    kImmediate,
+  };
+  std::vector<SackChunk::GapAckBlock> CreateGapAckBlocks() const;
+  void UpdateAckState(AckState new_state, absl::string_view reason);
+  static absl::string_view ToString(AckState ack_state);
+
+  const std::string log_prefix_;
+  // If a packet has ever been seen.
+  bool seen_packet_ = false;
+  Timer& delayed_ack_timer_;
+  AckState ack_state_ = AckState::kIdle;
+  UnwrappedTSN::Unwrapper tsn_unwrapper_;
+
+  // All TSNs up until (and including) this value have been seen.
+  UnwrappedTSN last_cumulative_acked_tsn_;
+  // Received TSNs that are not directly following `last_cumulative_acked_tsn_`.
+  std::set<UnwrappedTSN> additional_tsns;
+  std::set<UnwrappedTSN> duplicates_;
+};
+}  // namespace dcsctp
+
+#endif  // NET_DCSCTP_RX_DATA_TRACKER_H_