xref: /aosp_15_r20/external/webrtc/net/dcsctp/rx/data_tracker.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker #ifndef NET_DCSCTP_RX_DATA_TRACKER_H_
11*d9f75844SAndroid Build Coastguard Worker #define NET_DCSCTP_RX_DATA_TRACKER_H_
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <stddef.h>
14*d9f75844SAndroid Build Coastguard Worker #include <stdint.h>
15*d9f75844SAndroid Build Coastguard Worker 
16*d9f75844SAndroid Build Coastguard Worker #include <cstdint>
17*d9f75844SAndroid Build Coastguard Worker #include <set>
18*d9f75844SAndroid Build Coastguard Worker #include <string>
19*d9f75844SAndroid Build Coastguard Worker #include <utility>
20*d9f75844SAndroid Build Coastguard Worker #include <vector>
21*d9f75844SAndroid Build Coastguard Worker 
22*d9f75844SAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
23*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/common/sequence_numbers.h"
24*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/chunk/data_common.h"
25*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/chunk/sack_chunk.h"
26*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/packet/data.h"
27*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/public/dcsctp_handover_state.h"
28*d9f75844SAndroid Build Coastguard Worker #include "net/dcsctp/timer/timer.h"
29*d9f75844SAndroid Build Coastguard Worker 
30*d9f75844SAndroid Build Coastguard Worker namespace dcsctp {
31*d9f75844SAndroid Build Coastguard Worker 
32*d9f75844SAndroid Build Coastguard Worker // Keeps track of received DATA chunks and handles all logic for _when_ to
33*d9f75844SAndroid Build Coastguard Worker // create SACKs and also _how_ to generate them.
34*d9f75844SAndroid Build Coastguard Worker //
35*d9f75844SAndroid Build Coastguard Worker // It only uses TSNs to track delivery and doesn't need to be aware of streams.
36*d9f75844SAndroid Build Coastguard Worker //
37*d9f75844SAndroid Build Coastguard Worker // SACKs are optimally sent every second packet on connections with no packet
38*d9f75844SAndroid Build Coastguard Worker // loss. When packet loss is detected, it's sent for every packet. When SACKs
39*d9f75844SAndroid Build Coastguard Worker // are not sent directly, a timer is used to send a SACK delayed (by RTO/2, or
40*d9f75844SAndroid Build Coastguard Worker // 200ms, whatever is smallest).
41*d9f75844SAndroid Build Coastguard Worker class DataTracker {
42*d9f75844SAndroid Build Coastguard Worker  public:
43*d9f75844SAndroid Build Coastguard Worker   // The maximum number of duplicate TSNs that will be reported in a SACK.
44*d9f75844SAndroid Build Coastguard Worker   static constexpr size_t kMaxDuplicateTsnReported = 20;
45*d9f75844SAndroid Build Coastguard Worker   // The maximum number of gap-ack-blocks that will be reported in a SACK.
46*d9f75844SAndroid Build Coastguard Worker   static constexpr size_t kMaxGapAckBlocksReported = 20;
47*d9f75844SAndroid Build Coastguard Worker 
48*d9f75844SAndroid Build Coastguard Worker   // The maximum number of accepted in-flight DATA chunks. This indicates the
49*d9f75844SAndroid Build Coastguard Worker   // maximum difference from this buffer's last cumulative ack TSN, and any
50*d9f75844SAndroid Build Coastguard Worker   // received data. Data received beyond this limit will be dropped, which will
51*d9f75844SAndroid Build Coastguard Worker   // force the transmitter to send data that actually increases the last
52*d9f75844SAndroid Build Coastguard Worker   // cumulative acked TSN.
53*d9f75844SAndroid Build Coastguard Worker   static constexpr uint32_t kMaxAcceptedOutstandingFragments = 100000;
54*d9f75844SAndroid Build Coastguard Worker 
DataTracker(absl::string_view log_prefix,Timer * delayed_ack_timer,TSN peer_initial_tsn)55*d9f75844SAndroid Build Coastguard Worker   DataTracker(absl::string_view log_prefix,
56*d9f75844SAndroid Build Coastguard Worker               Timer* delayed_ack_timer,
57*d9f75844SAndroid Build Coastguard Worker               TSN peer_initial_tsn)
58*d9f75844SAndroid Build Coastguard Worker       : log_prefix_(std::string(log_prefix) + "dtrack: "),
59*d9f75844SAndroid Build Coastguard Worker         seen_packet_(false),
60*d9f75844SAndroid Build Coastguard Worker         delayed_ack_timer_(*delayed_ack_timer),
61*d9f75844SAndroid Build Coastguard Worker         last_cumulative_acked_tsn_(
62*d9f75844SAndroid Build Coastguard Worker             tsn_unwrapper_.Unwrap(TSN(*peer_initial_tsn - 1))) {}
63*d9f75844SAndroid Build Coastguard Worker 
64*d9f75844SAndroid Build Coastguard Worker   // Indicates if the provided TSN is valid. If this return false, the data
65*d9f75844SAndroid Build Coastguard Worker   // should be dropped and not added to any other buffers, which essentially
66*d9f75844SAndroid Build Coastguard Worker   // means that there is intentional packet loss.
67*d9f75844SAndroid Build Coastguard Worker   bool IsTSNValid(TSN tsn) const;
68*d9f75844SAndroid Build Coastguard Worker 
69*d9f75844SAndroid Build Coastguard Worker   // Call for every incoming data chunk. Returns `true` if `tsn` was seen for
70*d9f75844SAndroid Build Coastguard Worker   // the first time, and `false` if it has been seen before (a duplicate `tsn`).
71*d9f75844SAndroid Build Coastguard Worker   bool Observe(TSN tsn,
72*d9f75844SAndroid Build Coastguard Worker                AnyDataChunk::ImmediateAckFlag immediate_ack =
73*d9f75844SAndroid Build Coastguard Worker                    AnyDataChunk::ImmediateAckFlag(false));
74*d9f75844SAndroid Build Coastguard Worker   // Called at the end of processing an SCTP packet.
75*d9f75844SAndroid Build Coastguard Worker   void ObservePacketEnd();
76*d9f75844SAndroid Build Coastguard Worker 
77*d9f75844SAndroid Build Coastguard Worker   // Called for incoming FORWARD-TSN/I-FORWARD-TSN chunks
78*d9f75844SAndroid Build Coastguard Worker   void HandleForwardTsn(TSN new_cumulative_ack);
79*d9f75844SAndroid Build Coastguard Worker 
80*d9f75844SAndroid Build Coastguard Worker   // Indicates if a SACK should be sent. There may be other reasons to send a
81*d9f75844SAndroid Build Coastguard Worker   // SACK, but if this function indicates so, it should be sent as soon as
82*d9f75844SAndroid Build Coastguard Worker   // possible. Calling this function will make it clear a flag so that if it's
83*d9f75844SAndroid Build Coastguard Worker   // called again, it will probably return false.
84*d9f75844SAndroid Build Coastguard Worker   //
85*d9f75844SAndroid Build Coastguard Worker   // If the delayed ack timer is running, this method will return false _unless_
86*d9f75844SAndroid Build Coastguard Worker   // `also_if_delayed` is set to true. Then it will return true as well.
87*d9f75844SAndroid Build Coastguard Worker   bool ShouldSendAck(bool also_if_delayed = false);
88*d9f75844SAndroid Build Coastguard Worker 
89*d9f75844SAndroid Build Coastguard Worker   // Returns the last cumulative ack TSN - the last seen data chunk's TSN
90*d9f75844SAndroid Build Coastguard Worker   // value before any packet loss was detected.
last_cumulative_acked_tsn()91*d9f75844SAndroid Build Coastguard Worker   TSN last_cumulative_acked_tsn() const {
92*d9f75844SAndroid Build Coastguard Worker     return TSN(last_cumulative_acked_tsn_.Wrap());
93*d9f75844SAndroid Build Coastguard Worker   }
94*d9f75844SAndroid Build Coastguard Worker 
95*d9f75844SAndroid Build Coastguard Worker   // Returns true if the received `tsn` would increase the cumulative ack TSN.
96*d9f75844SAndroid Build Coastguard Worker   bool will_increase_cum_ack_tsn(TSN tsn) const;
97*d9f75844SAndroid Build Coastguard Worker 
98*d9f75844SAndroid Build Coastguard Worker   // Forces `ShouldSendSack` to return true.
99*d9f75844SAndroid Build Coastguard Worker   void ForceImmediateSack();
100*d9f75844SAndroid Build Coastguard Worker 
101*d9f75844SAndroid Build Coastguard Worker   // Note that this will clear `duplicates_`, so every SackChunk that is
102*d9f75844SAndroid Build Coastguard Worker   // consumed must be sent.
103*d9f75844SAndroid Build Coastguard Worker   SackChunk CreateSelectiveAck(size_t a_rwnd);
104*d9f75844SAndroid Build Coastguard Worker 
105*d9f75844SAndroid Build Coastguard Worker   void HandleDelayedAckTimerExpiry();
106*d9f75844SAndroid Build Coastguard Worker 
107*d9f75844SAndroid Build Coastguard Worker   HandoverReadinessStatus GetHandoverReadiness() const;
108*d9f75844SAndroid Build Coastguard Worker 
109*d9f75844SAndroid Build Coastguard Worker   void AddHandoverState(DcSctpSocketHandoverState& state);
110*d9f75844SAndroid Build Coastguard Worker   void RestoreFromState(const DcSctpSocketHandoverState& state);
111*d9f75844SAndroid Build Coastguard Worker 
112*d9f75844SAndroid Build Coastguard Worker  private:
113*d9f75844SAndroid Build Coastguard Worker   enum class AckState {
114*d9f75844SAndroid Build Coastguard Worker     // No need to send an ACK.
115*d9f75844SAndroid Build Coastguard Worker     kIdle,
116*d9f75844SAndroid Build Coastguard Worker 
117*d9f75844SAndroid Build Coastguard Worker     // Has received data chunks (but not yet end of packet).
118*d9f75844SAndroid Build Coastguard Worker     kBecomingDelayed,
119*d9f75844SAndroid Build Coastguard Worker 
120*d9f75844SAndroid Build Coastguard Worker     // Has received data chunks and the end of a packet. Delayed ack timer is
121*d9f75844SAndroid Build Coastguard Worker     // running and a SACK will be sent on expiry, or if DATA is sent, or after
122*d9f75844SAndroid Build Coastguard Worker     // next packet with data.
123*d9f75844SAndroid Build Coastguard Worker     kDelayed,
124*d9f75844SAndroid Build Coastguard Worker 
125*d9f75844SAndroid Build Coastguard Worker     // Send a SACK immediately after handling this packet.
126*d9f75844SAndroid Build Coastguard Worker     kImmediate,
127*d9f75844SAndroid Build Coastguard Worker   };
128*d9f75844SAndroid Build Coastguard Worker 
129*d9f75844SAndroid Build Coastguard Worker   // Represents ranges of TSNs that have been received that are not directly
130*d9f75844SAndroid Build Coastguard Worker   // following the last cumulative acked TSN. This information is returned to
131*d9f75844SAndroid Build Coastguard Worker   // the sender in the "gap ack blocks" in the SACK chunk. The blocks are always
132*d9f75844SAndroid Build Coastguard Worker   // non-overlapping and non-adjacent.
133*d9f75844SAndroid Build Coastguard Worker   class AdditionalTsnBlocks {
134*d9f75844SAndroid Build Coastguard Worker    public:
135*d9f75844SAndroid Build Coastguard Worker     // Represents an inclusive range of received TSNs, i.e. [first, last].
136*d9f75844SAndroid Build Coastguard Worker     struct TsnRange {
TsnRangeTsnRange137*d9f75844SAndroid Build Coastguard Worker       TsnRange(UnwrappedTSN first, UnwrappedTSN last)
138*d9f75844SAndroid Build Coastguard Worker           : first(first), last(last) {}
139*d9f75844SAndroid Build Coastguard Worker       UnwrappedTSN first;
140*d9f75844SAndroid Build Coastguard Worker       UnwrappedTSN last;
141*d9f75844SAndroid Build Coastguard Worker     };
142*d9f75844SAndroid Build Coastguard Worker 
143*d9f75844SAndroid Build Coastguard Worker     // Adds a TSN to the set. This will try to expand any existing block and
144*d9f75844SAndroid Build Coastguard Worker     // might merge blocks to ensure that all blocks are non-adjacent. If a
145*d9f75844SAndroid Build Coastguard Worker     // current block can't be expanded, a new block is created.
146*d9f75844SAndroid Build Coastguard Worker     //
147*d9f75844SAndroid Build Coastguard Worker     // The return value indicates if `tsn` was added. If false is returned, the
148*d9f75844SAndroid Build Coastguard Worker     // `tsn` was already represented in one of the blocks.
149*d9f75844SAndroid Build Coastguard Worker     bool Add(UnwrappedTSN tsn);
150*d9f75844SAndroid Build Coastguard Worker 
151*d9f75844SAndroid Build Coastguard Worker     // Erases all TSNs up to, and including `tsn`. This will remove all blocks
152*d9f75844SAndroid Build Coastguard Worker     // that are completely below `tsn` and may truncate a block where `tsn` is
153*d9f75844SAndroid Build Coastguard Worker     // within that block. In that case, the frontmost block's start TSN will be
154*d9f75844SAndroid Build Coastguard Worker     // the next following tsn after `tsn`.
155*d9f75844SAndroid Build Coastguard Worker     void EraseTo(UnwrappedTSN tsn);
156*d9f75844SAndroid Build Coastguard Worker 
157*d9f75844SAndroid Build Coastguard Worker     // Removes the first block. Must not be called on an empty set.
158*d9f75844SAndroid Build Coastguard Worker     void PopFront();
159*d9f75844SAndroid Build Coastguard Worker 
blocks()160*d9f75844SAndroid Build Coastguard Worker     const std::vector<TsnRange>& blocks() const { return blocks_; }
161*d9f75844SAndroid Build Coastguard Worker 
empty()162*d9f75844SAndroid Build Coastguard Worker     bool empty() const { return blocks_.empty(); }
163*d9f75844SAndroid Build Coastguard Worker 
front()164*d9f75844SAndroid Build Coastguard Worker     const TsnRange& front() const { return blocks_.front(); }
165*d9f75844SAndroid Build Coastguard Worker 
166*d9f75844SAndroid Build Coastguard Worker    private:
167*d9f75844SAndroid Build Coastguard Worker     // A sorted vector of non-overlapping and non-adjacent blocks.
168*d9f75844SAndroid Build Coastguard Worker     std::vector<TsnRange> blocks_;
169*d9f75844SAndroid Build Coastguard Worker   };
170*d9f75844SAndroid Build Coastguard Worker 
171*d9f75844SAndroid Build Coastguard Worker   std::vector<SackChunk::GapAckBlock> CreateGapAckBlocks() const;
172*d9f75844SAndroid Build Coastguard Worker   void UpdateAckState(AckState new_state, absl::string_view reason);
173*d9f75844SAndroid Build Coastguard Worker   static absl::string_view ToString(AckState ack_state);
174*d9f75844SAndroid Build Coastguard Worker 
175*d9f75844SAndroid Build Coastguard Worker   const std::string log_prefix_;
176*d9f75844SAndroid Build Coastguard Worker   // If a packet has ever been seen.
177*d9f75844SAndroid Build Coastguard Worker   bool seen_packet_;
178*d9f75844SAndroid Build Coastguard Worker   Timer& delayed_ack_timer_;
179*d9f75844SAndroid Build Coastguard Worker   AckState ack_state_ = AckState::kIdle;
180*d9f75844SAndroid Build Coastguard Worker   UnwrappedTSN::Unwrapper tsn_unwrapper_;
181*d9f75844SAndroid Build Coastguard Worker 
182*d9f75844SAndroid Build Coastguard Worker   // All TSNs up until (and including) this value have been seen.
183*d9f75844SAndroid Build Coastguard Worker   UnwrappedTSN last_cumulative_acked_tsn_;
184*d9f75844SAndroid Build Coastguard Worker   // Received TSNs that are not directly following `last_cumulative_acked_tsn_`.
185*d9f75844SAndroid Build Coastguard Worker   AdditionalTsnBlocks additional_tsn_blocks_;
186*d9f75844SAndroid Build Coastguard Worker   std::set<TSN> duplicate_tsns_;
187*d9f75844SAndroid Build Coastguard Worker };
188*d9f75844SAndroid Build Coastguard Worker }  // namespace dcsctp
189*d9f75844SAndroid Build Coastguard Worker 
190*d9f75844SAndroid Build Coastguard Worker #endif  // NET_DCSCTP_RX_DATA_TRACKER_H_
191