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