1 /* 2 * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 #ifndef NET_DCSCTP_TX_RETRANSMISSION_QUEUE_H_ 11 #define NET_DCSCTP_TX_RETRANSMISSION_QUEUE_H_ 12 13 #include <cstdint> 14 #include <functional> 15 #include <map> 16 #include <set> 17 #include <string> 18 #include <utility> 19 #include <vector> 20 21 #include "absl/strings/string_view.h" 22 #include "absl/types/optional.h" 23 #include "api/array_view.h" 24 #include "net/dcsctp/common/sequence_numbers.h" 25 #include "net/dcsctp/packet/chunk/forward_tsn_chunk.h" 26 #include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h" 27 #include "net/dcsctp/packet/chunk/sack_chunk.h" 28 #include "net/dcsctp/packet/data.h" 29 #include "net/dcsctp/public/dcsctp_handover_state.h" 30 #include "net/dcsctp/public/dcsctp_options.h" 31 #include "net/dcsctp/public/dcsctp_socket.h" 32 #include "net/dcsctp/timer/timer.h" 33 #include "net/dcsctp/tx/outstanding_data.h" 34 #include "net/dcsctp/tx/retransmission_timeout.h" 35 #include "net/dcsctp/tx/send_queue.h" 36 37 namespace dcsctp { 38 39 // The RetransmissionQueue manages all DATA/I-DATA chunks that are in-flight and 40 // schedules them to be retransmitted if necessary. Chunks are retransmitted 41 // when they have been lost for a number of consecutive SACKs, or when the 42 // retransmission timer, `t3_rtx` expires. 43 // 44 // As congestion control is tightly connected with the state of transmitted 45 // packets, that's also managed here to limit the amount of data that is 46 // in-flight (sent, but not yet acknowledged). 47 class RetransmissionQueue { 48 public: 49 static constexpr size_t kMinimumFragmentedPayload = 10; 50 using State = OutstandingData::State; 51 // Creates a RetransmissionQueue which will send data using `my_initial_tsn` 52 // (or a value from `DcSctpSocketHandoverState` if given) as the first TSN 53 // to use for sent fragments. It will poll data from `send_queue`. When SACKs 54 // are received, it will estimate the RTT, and call `on_new_rtt`. When an 55 // outstanding chunk has been ACKed, it will call 56 // `on_clear_retransmission_counter` and will also use `t3_rtx`, which is the 57 // SCTP retransmission timer to manage retransmissions. 58 RetransmissionQueue(absl::string_view log_prefix, 59 DcSctpSocketCallbacks* callbacks, 60 TSN my_initial_tsn, 61 size_t a_rwnd, 62 SendQueue& send_queue, 63 std::function<void(DurationMs rtt)> on_new_rtt, 64 std::function<void()> on_clear_retransmission_counter, 65 Timer& t3_rtx, 66 const DcSctpOptions& options, 67 bool supports_partial_reliability = true, 68 bool use_message_interleaving = false); 69 70 // Handles a received SACK. Returns true if the `sack` was processed and 71 // false if it was discarded due to received out-of-order and not relevant. 72 bool HandleSack(TimeMs now, const SackChunk& sack); 73 74 // Handles an expired retransmission timer. 75 void HandleT3RtxTimerExpiry(); 76 has_data_to_be_fast_retransmitted()77 bool has_data_to_be_fast_retransmitted() const { 78 return outstanding_data_.has_data_to_be_fast_retransmitted(); 79 } 80 81 // Returns a list of chunks to "fast retransmit" that would fit in one SCTP 82 // packet with `bytes_in_packet` bytes available. The current value 83 // of `cwnd` is ignored. 84 std::vector<std::pair<TSN, Data>> GetChunksForFastRetransmit( 85 size_t bytes_in_packet); 86 87 // Returns a list of chunks to send that would fit in one SCTP packet with 88 // `bytes_remaining_in_packet` bytes available. This may be further limited by 89 // the congestion control windows. Note that `ShouldSendForwardTSN` must be 90 // called prior to this method, to abandon expired chunks, as this method will 91 // not expire any chunks. 92 std::vector<std::pair<TSN, Data>> GetChunksToSend( 93 TimeMs now, 94 size_t bytes_remaining_in_packet); 95 96 // Returns the internal state of all queued chunks. This is only used in 97 // unit-tests. GetChunkStatesForTesting()98 std::vector<std::pair<TSN, OutstandingData::State>> GetChunkStatesForTesting() 99 const { 100 return outstanding_data_.GetChunkStatesForTesting(); 101 } 102 103 // Returns the next TSN that will be allocated for sent DATA chunks. next_tsn()104 TSN next_tsn() const { return outstanding_data_.next_tsn().Wrap(); } 105 106 // Returns the size of the congestion window, in bytes. This is the number of 107 // bytes that may be in-flight. cwnd()108 size_t cwnd() const { return cwnd_; } 109 110 // Overrides the current congestion window size. set_cwnd(size_t cwnd)111 void set_cwnd(size_t cwnd) { cwnd_ = cwnd; } 112 113 // Returns the current receiver window size. rwnd()114 size_t rwnd() const { return rwnd_; } 115 116 // Returns the number of bytes of packets that are in-flight. outstanding_bytes()117 size_t outstanding_bytes() const { 118 return outstanding_data_.outstanding_bytes(); 119 } 120 121 // Returns the number of DATA chunks that are in-flight. outstanding_items()122 size_t outstanding_items() const { 123 return outstanding_data_.outstanding_items(); 124 } 125 126 // Indicates if the congestion control algorithm allows data to be sent. 127 bool can_send_data() const; 128 129 // Given the current time `now`, it will evaluate if there are chunks that 130 // have expired and that need to be discarded. It returns true if a 131 // FORWARD-TSN should be sent. 132 bool ShouldSendForwardTsn(TimeMs now); 133 134 // Creates a FORWARD-TSN chunk. CreateForwardTsn()135 ForwardTsnChunk CreateForwardTsn() const { 136 return outstanding_data_.CreateForwardTsn(); 137 } 138 139 // Creates an I-FORWARD-TSN chunk. CreateIForwardTsn()140 IForwardTsnChunk CreateIForwardTsn() const { 141 return outstanding_data_.CreateIForwardTsn(); 142 } 143 144 // See the SendQueue for a longer description of these methods related 145 // to stream resetting. 146 void PrepareResetStream(StreamID stream_id); 147 bool HasStreamsReadyToBeReset() const; GetStreamsReadyToBeReset()148 std::vector<StreamID> GetStreamsReadyToBeReset() const { 149 return send_queue_.GetStreamsReadyToBeReset(); 150 } 151 void CommitResetStreams(); 152 void RollbackResetStreams(); 153 154 HandoverReadinessStatus GetHandoverReadiness() const; 155 156 void AddHandoverState(DcSctpSocketHandoverState& state); 157 void RestoreFromState(const DcSctpSocketHandoverState& state); 158 159 private: 160 enum class CongestionAlgorithmPhase { 161 kSlowStart, 162 kCongestionAvoidance, 163 }; 164 165 bool IsConsistent() const; 166 167 // Returns how large a chunk will be, serialized, carrying the data 168 size_t GetSerializedChunkSize(const Data& data) const; 169 170 // Indicates if the congestion control algorithm is in "fast recovery". is_in_fast_recovery()171 bool is_in_fast_recovery() const { 172 return fast_recovery_exit_tsn_.has_value(); 173 } 174 175 // Indicates if the provided SACK is valid given what has previously been 176 // received. If it returns false, the SACK is most likely a duplicate of 177 // something already seen, so this returning false doesn't necessarily mean 178 // that the SACK is illegal. 179 bool IsSackValid(const SackChunk& sack) const; 180 181 // When a SACK chunk is received, this method will be called which _may_ call 182 // into the `RetransmissionTimeout` to update the RTO. 183 void UpdateRTT(TimeMs now, UnwrappedTSN cumulative_tsn_ack); 184 185 // If the congestion control is in "fast recovery mode", this may be exited 186 // now. 187 void MaybeExitFastRecovery(UnwrappedTSN cumulative_tsn_ack); 188 189 // If chunks have been ACKed, stop the retransmission timer. 190 void StopT3RtxTimerOnIncreasedCumulativeTsnAck( 191 UnwrappedTSN cumulative_tsn_ack); 192 193 // Update the congestion control algorithm given as the cumulative ack TSN 194 // value has increased, as reported in an incoming SACK chunk. 195 void HandleIncreasedCumulativeTsnAck(size_t outstanding_bytes, 196 size_t total_bytes_acked); 197 // Update the congestion control algorithm, given as packet loss has been 198 // detected, as reported in an incoming SACK chunk. 199 void HandlePacketLoss(UnwrappedTSN highest_tsn_acked); 200 // Update the view of the receiver window size. 201 void UpdateReceiverWindow(uint32_t a_rwnd); 202 // If there is data sent and not ACKED, ensure that the retransmission timer 203 // is running. 204 void StartT3RtxTimerIfOutstandingData(); 205 206 // Returns the current congestion control algorithm phase. phase()207 CongestionAlgorithmPhase phase() const { 208 return (cwnd_ <= ssthresh_) 209 ? CongestionAlgorithmPhase::kSlowStart 210 : CongestionAlgorithmPhase::kCongestionAvoidance; 211 } 212 213 // Returns the number of bytes that may be sent in a single packet according 214 // to the congestion control algorithm. 215 size_t max_bytes_to_send() const; 216 217 DcSctpSocketCallbacks& callbacks_; 218 const DcSctpOptions options_; 219 // The minimum bytes required to be available in the congestion window to 220 // allow packets to be sent - to avoid sending too small packets. 221 const size_t min_bytes_required_to_send_; 222 // If the peer supports RFC3758 - SCTP Partial Reliability Extension. 223 const bool partial_reliability_; 224 const std::string log_prefix_; 225 // The size of the data chunk (DATA/I-DATA) header that is used. 226 const size_t data_chunk_header_size_; 227 // Called when a new RTT measurement has been done 228 const std::function<void(DurationMs rtt)> on_new_rtt_; 229 // Called when a SACK has been seen that cleared the retransmission counter. 230 const std::function<void()> on_clear_retransmission_counter_; 231 // The retransmission counter. 232 Timer& t3_rtx_; 233 // Unwraps TSNs 234 UnwrappedTSN::Unwrapper tsn_unwrapper_; 235 236 // Congestion Window. Number of bytes that may be in-flight (sent, not acked). 237 size_t cwnd_; 238 // Receive Window. Number of bytes available in the receiver's RX buffer. 239 size_t rwnd_; 240 // Slow Start Threshold. See RFC4960. 241 size_t ssthresh_; 242 // Partial Bytes Acked. See RFC4960. 243 size_t partial_bytes_acked_; 244 // If set, fast recovery is enabled until this TSN has been cumulative 245 // acked. 246 absl::optional<UnwrappedTSN> fast_recovery_exit_tsn_ = absl::nullopt; 247 248 // The send queue. 249 SendQueue& send_queue_; 250 // All the outstanding data chunks that are in-flight and that have not been 251 // cumulative acked. Note that it also contains chunks that have been acked in 252 // gap ack blocks. 253 OutstandingData outstanding_data_; 254 }; 255 } // namespace dcsctp 256 257 #endif // NET_DCSCTP_TX_RETRANSMISSION_QUEUE_H_ 258