summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/net/dcsctp/tx/retransmission_queue.h
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/net/dcsctp/tx/retransmission_queue.h')
-rw-r--r--third_party/libwebrtc/net/dcsctp/tx/retransmission_queue.h257
1 files changed, 257 insertions, 0 deletions
diff --git a/third_party/libwebrtc/net/dcsctp/tx/retransmission_queue.h b/third_party/libwebrtc/net/dcsctp/tx/retransmission_queue.h
new file mode 100644
index 0000000000..830c0b346d
--- /dev/null
+++ b/third_party/libwebrtc/net/dcsctp/tx/retransmission_queue.h
@@ -0,0 +1,257 @@
+/*
+ * 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_TX_RETRANSMISSION_QUEUE_H_
+#define NET_DCSCTP_TX_RETRANSMISSION_QUEUE_H_
+
+#include <cstdint>
+#include <functional>
+#include <map>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/array_view.h"
+#include "net/dcsctp/common/sequence_numbers.h"
+#include "net/dcsctp/packet/chunk/forward_tsn_chunk.h"
+#include "net/dcsctp/packet/chunk/iforward_tsn_chunk.h"
+#include "net/dcsctp/packet/chunk/sack_chunk.h"
+#include "net/dcsctp/packet/data.h"
+#include "net/dcsctp/public/dcsctp_handover_state.h"
+#include "net/dcsctp/public/dcsctp_options.h"
+#include "net/dcsctp/public/dcsctp_socket.h"
+#include "net/dcsctp/timer/timer.h"
+#include "net/dcsctp/tx/outstanding_data.h"
+#include "net/dcsctp/tx/retransmission_timeout.h"
+#include "net/dcsctp/tx/send_queue.h"
+
+namespace dcsctp {
+
+// The RetransmissionQueue manages all DATA/I-DATA chunks that are in-flight and
+// schedules them to be retransmitted if necessary. Chunks are retransmitted
+// when they have been lost for a number of consecutive SACKs, or when the
+// retransmission timer, `t3_rtx` expires.
+//
+// As congestion control is tightly connected with the state of transmitted
+// packets, that's also managed here to limit the amount of data that is
+// in-flight (sent, but not yet acknowledged).
+class RetransmissionQueue {
+ public:
+ static constexpr size_t kMinimumFragmentedPayload = 10;
+ using State = OutstandingData::State;
+ // Creates a RetransmissionQueue which will send data using `my_initial_tsn`
+ // (or a value from `DcSctpSocketHandoverState` if given) as the first TSN
+ // to use for sent fragments. It will poll data from `send_queue`. When SACKs
+ // are received, it will estimate the RTT, and call `on_new_rtt`. When an
+ // outstanding chunk has been ACKed, it will call
+ // `on_clear_retransmission_counter` and will also use `t3_rtx`, which is the
+ // SCTP retransmission timer to manage retransmissions.
+ RetransmissionQueue(absl::string_view log_prefix,
+ DcSctpSocketCallbacks* callbacks,
+ TSN my_initial_tsn,
+ size_t a_rwnd,
+ SendQueue& send_queue,
+ std::function<void(DurationMs rtt)> on_new_rtt,
+ std::function<void()> on_clear_retransmission_counter,
+ Timer& t3_rtx,
+ const DcSctpOptions& options,
+ bool supports_partial_reliability = true,
+ bool use_message_interleaving = false);
+
+ // Handles a received SACK. Returns true if the `sack` was processed and
+ // false if it was discarded due to received out-of-order and not relevant.
+ bool HandleSack(TimeMs now, const SackChunk& sack);
+
+ // Handles an expired retransmission timer.
+ void HandleT3RtxTimerExpiry();
+
+ bool has_data_to_be_fast_retransmitted() const {
+ return outstanding_data_.has_data_to_be_fast_retransmitted();
+ }
+
+ // Returns a list of chunks to "fast retransmit" that would fit in one SCTP
+ // packet with `bytes_in_packet` bytes available. The current value
+ // of `cwnd` is ignored.
+ std::vector<std::pair<TSN, Data>> GetChunksForFastRetransmit(
+ size_t bytes_in_packet);
+
+ // Returns a list of chunks to send that would fit in one SCTP packet with
+ // `bytes_remaining_in_packet` bytes available. This may be further limited by
+ // the congestion control windows. Note that `ShouldSendForwardTSN` must be
+ // called prior to this method, to abandon expired chunks, as this method will
+ // not expire any chunks.
+ std::vector<std::pair<TSN, Data>> GetChunksToSend(
+ TimeMs now,
+ size_t bytes_remaining_in_packet);
+
+ // Returns the internal state of all queued chunks. This is only used in
+ // unit-tests.
+ std::vector<std::pair<TSN, OutstandingData::State>> GetChunkStatesForTesting()
+ const {
+ return outstanding_data_.GetChunkStatesForTesting();
+ }
+
+ // Returns the next TSN that will be allocated for sent DATA chunks.
+ TSN next_tsn() const { return outstanding_data_.next_tsn().Wrap(); }
+
+ // Returns the size of the congestion window, in bytes. This is the number of
+ // bytes that may be in-flight.
+ size_t cwnd() const { return cwnd_; }
+
+ // Overrides the current congestion window size.
+ void set_cwnd(size_t cwnd) { cwnd_ = cwnd; }
+
+ // Returns the current receiver window size.
+ size_t rwnd() const { return rwnd_; }
+
+ // Returns the number of bytes of packets that are in-flight.
+ size_t outstanding_bytes() const {
+ return outstanding_data_.outstanding_bytes();
+ }
+
+ // Returns the number of DATA chunks that are in-flight.
+ size_t outstanding_items() const {
+ return outstanding_data_.outstanding_items();
+ }
+
+ // Indicates if the congestion control algorithm allows data to be sent.
+ bool can_send_data() const;
+
+ // Given the current time `now`, it will evaluate if there are chunks that
+ // have expired and that need to be discarded. It returns true if a
+ // FORWARD-TSN should be sent.
+ bool ShouldSendForwardTsn(TimeMs now);
+
+ // Creates a FORWARD-TSN chunk.
+ ForwardTsnChunk CreateForwardTsn() const {
+ return outstanding_data_.CreateForwardTsn();
+ }
+
+ // Creates an I-FORWARD-TSN chunk.
+ IForwardTsnChunk CreateIForwardTsn() const {
+ return outstanding_data_.CreateIForwardTsn();
+ }
+
+ // See the SendQueue for a longer description of these methods related
+ // to stream resetting.
+ void PrepareResetStream(StreamID stream_id);
+ bool HasStreamsReadyToBeReset() const;
+ std::vector<StreamID> GetStreamsReadyToBeReset() const {
+ return send_queue_.GetStreamsReadyToBeReset();
+ }
+ void CommitResetStreams();
+ void RollbackResetStreams();
+
+ HandoverReadinessStatus GetHandoverReadiness() const;
+
+ void AddHandoverState(DcSctpSocketHandoverState& state);
+ void RestoreFromState(const DcSctpSocketHandoverState& state);
+
+ private:
+ enum class CongestionAlgorithmPhase {
+ kSlowStart,
+ kCongestionAvoidance,
+ };
+
+ bool IsConsistent() const;
+
+ // Returns how large a chunk will be, serialized, carrying the data
+ size_t GetSerializedChunkSize(const Data& data) const;
+
+ // Indicates if the congestion control algorithm is in "fast recovery".
+ bool is_in_fast_recovery() const {
+ return fast_recovery_exit_tsn_.has_value();
+ }
+
+ // Indicates if the provided SACK is valid given what has previously been
+ // received. If it returns false, the SACK is most likely a duplicate of
+ // something already seen, so this returning false doesn't necessarily mean
+ // that the SACK is illegal.
+ bool IsSackValid(const SackChunk& sack) const;
+
+ // When a SACK chunk is received, this method will be called which _may_ call
+ // into the `RetransmissionTimeout` to update the RTO.
+ void UpdateRTT(TimeMs now, UnwrappedTSN cumulative_tsn_ack);
+
+ // If the congestion control is in "fast recovery mode", this may be exited
+ // now.
+ void MaybeExitFastRecovery(UnwrappedTSN cumulative_tsn_ack);
+
+ // If chunks have been ACKed, stop the retransmission timer.
+ void StopT3RtxTimerOnIncreasedCumulativeTsnAck(
+ UnwrappedTSN cumulative_tsn_ack);
+
+ // Update the congestion control algorithm given as the cumulative ack TSN
+ // value has increased, as reported in an incoming SACK chunk.
+ void HandleIncreasedCumulativeTsnAck(size_t outstanding_bytes,
+ size_t total_bytes_acked);
+ // Update the congestion control algorithm, given as packet loss has been
+ // detected, as reported in an incoming SACK chunk.
+ void HandlePacketLoss(UnwrappedTSN highest_tsn_acked);
+ // Update the view of the receiver window size.
+ void UpdateReceiverWindow(uint32_t a_rwnd);
+ // If there is data sent and not ACKED, ensure that the retransmission timer
+ // is running.
+ void StartT3RtxTimerIfOutstandingData();
+
+ // Returns the current congestion control algorithm phase.
+ CongestionAlgorithmPhase phase() const {
+ return (cwnd_ <= ssthresh_)
+ ? CongestionAlgorithmPhase::kSlowStart
+ : CongestionAlgorithmPhase::kCongestionAvoidance;
+ }
+
+ // Returns the number of bytes that may be sent in a single packet according
+ // to the congestion control algorithm.
+ size_t max_bytes_to_send() const;
+
+ DcSctpSocketCallbacks& callbacks_;
+ const DcSctpOptions options_;
+ // The minimum bytes required to be available in the congestion window to
+ // allow packets to be sent - to avoid sending too small packets.
+ const size_t min_bytes_required_to_send_;
+ // If the peer supports RFC3758 - SCTP Partial Reliability Extension.
+ const bool partial_reliability_;
+ const std::string log_prefix_;
+ // The size of the data chunk (DATA/I-DATA) header that is used.
+ const size_t data_chunk_header_size_;
+ // Called when a new RTT measurement has been done
+ const std::function<void(DurationMs rtt)> on_new_rtt_;
+ // Called when a SACK has been seen that cleared the retransmission counter.
+ const std::function<void()> on_clear_retransmission_counter_;
+ // The retransmission counter.
+ Timer& t3_rtx_;
+ // Unwraps TSNs
+ UnwrappedTSN::Unwrapper tsn_unwrapper_;
+
+ // Congestion Window. Number of bytes that may be in-flight (sent, not acked).
+ size_t cwnd_;
+ // Receive Window. Number of bytes available in the receiver's RX buffer.
+ size_t rwnd_;
+ // Slow Start Threshold. See RFC4960.
+ size_t ssthresh_;
+ // Partial Bytes Acked. See RFC4960.
+ size_t partial_bytes_acked_;
+ // If set, fast recovery is enabled until this TSN has been cumulative
+ // acked.
+ absl::optional<UnwrappedTSN> fast_recovery_exit_tsn_ = absl::nullopt;
+
+ // The send queue.
+ SendQueue& send_queue_;
+ // All the outstanding data chunks that are in-flight and that have not been
+ // cumulative acked. Note that it also contains chunks that have been acked in
+ // gap ack blocks.
+ OutstandingData outstanding_data_;
+};
+} // namespace dcsctp
+
+#endif // NET_DCSCTP_TX_RETRANSMISSION_QUEUE_H_