• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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