xref: /aosp_15_r20/external/webrtc/net/dcsctp/rx/reassembly_queue.h (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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_RX_REASSEMBLY_QUEUE_H_
11 #define NET_DCSCTP_RX_REASSEMBLY_QUEUE_H_
12 
13 #include <stddef.h>
14 
15 #include <cstdint>
16 #include <memory>
17 #include <set>
18 #include <string>
19 #include <utility>
20 #include <vector>
21 
22 #include "absl/strings/string_view.h"
23 #include "api/array_view.h"
24 #include "net/dcsctp/common/internal_types.h"
25 #include "net/dcsctp/common/sequence_numbers.h"
26 #include "net/dcsctp/packet/chunk/forward_tsn_common.h"
27 #include "net/dcsctp/packet/data.h"
28 #include "net/dcsctp/packet/parameter/outgoing_ssn_reset_request_parameter.h"
29 #include "net/dcsctp/packet/parameter/reconfiguration_response_parameter.h"
30 #include "net/dcsctp/public/dcsctp_handover_state.h"
31 #include "net/dcsctp/public/dcsctp_message.h"
32 #include "net/dcsctp/rx/reassembly_streams.h"
33 
34 namespace dcsctp {
35 
36 // Contains the received DATA chunks that haven't yet been reassembled, and
37 // reassembles chunks when possible.
38 //
39 // The actual assembly is handled by an implementation of the
40 // `ReassemblyStreams` interface.
41 //
42 // Except for reassembling fragmented messages, this class will also handle two
43 // less common operations; To handle the receiver-side of partial reliability
44 // (limited number of retransmissions or limited message lifetime) as well as
45 // stream resetting, which is used when a sender wishes to close a data channel.
46 //
47 // Partial reliability is handled when a FORWARD-TSN or I-FORWARD-TSN chunk is
48 // received, and it will simply delete any chunks matching the parameters in
49 // that chunk. This is mainly implemented in ReassemblyStreams.
50 //
51 // Resetting streams is handled when a RECONFIG chunks is received, with an
52 // "Outgoing SSN Reset Request" parameter. That parameter will contain a list of
53 // streams to reset, and a `sender_last_assigned_tsn`. If this TSN is not yet
54 // seen, the stream cannot be directly reset, and this class will respond that
55 // the reset is "deferred". But if this TSN provided is known, the stream can be
56 // immediately be reset.
57 //
58 // The ReassemblyQueue has a maximum size, as it would otherwise be an DoS
59 // attack vector where a peer could consume all memory of the other peer by
60 // sending a lot of ordered chunks, but carefully withholding an early one. It
61 // also has a watermark limit, which the caller can query is the number of bytes
62 // is above that limit. This is used by the caller to be selective in what to
63 // add to the reassembly queue, so that it's not exhausted. The caller is
64 // expected to call `is_full` prior to adding data to the queue and to act
65 // accordingly if the queue is full.
66 class ReassemblyQueue {
67  public:
68   // When the queue is filled over this fraction (of its maximum size), the
69   // socket should restrict incoming data to avoid filling up the queue.
70   static constexpr float kHighWatermarkLimit = 0.9;
71 
72   ReassemblyQueue(absl::string_view log_prefix,
73                   TSN peer_initial_tsn,
74                   size_t max_size_bytes,
75                   bool use_message_interleaving = false);
76 
77   // Adds a data chunk to the queue, with a `tsn` and other parameters in
78   // `data`.
79   void Add(TSN tsn, Data data);
80 
81   // Indicates if the reassembly queue has any reassembled messages that can be
82   // retrieved by calling `FlushMessages`.
HasMessages()83   bool HasMessages() const { return !reassembled_messages_.empty(); }
84 
85   // Returns any reassembled messages.
86   std::vector<DcSctpMessage> FlushMessages();
87 
88   // Handle a ForwardTSN chunk, when the sender has indicated that the received
89   // (this class) should forget about some chunks. This is used to implement
90   // partial reliability.
91   void Handle(const AnyForwardTsnChunk& forward_tsn);
92 
93   // Given the reset stream request and the current cum_tsn_ack, might either
94   // reset the streams directly (returns kSuccessPerformed), or at a later time,
95   // by entering the "deferred reset processing" mode (returns kInProgress).
96   ReconfigurationResponseParameter::Result ResetStreams(
97       const OutgoingSSNResetRequestParameter& req,
98       TSN cum_tsn_ack);
99 
100   // Given the current (updated) cum_tsn_ack, might leave "defererred reset
101   // processing" mode and reset streams. Returns true if so.
102   bool MaybeResetStreamsDeferred(TSN cum_ack_tsn);
103 
104   // The number of payload bytes that have been queued. Note that the actual
105   // memory usage is higher due to additional overhead of tracking received
106   // data.
queued_bytes()107   size_t queued_bytes() const { return queued_bytes_; }
108 
109   // The remaining bytes until the queue has reached the watermark limit.
remaining_bytes()110   size_t remaining_bytes() const { return watermark_bytes_ - queued_bytes_; }
111 
112   // Indicates if the queue is full. Data should not be added to the queue when
113   // it's full.
is_full()114   bool is_full() const { return queued_bytes_ >= max_size_bytes_; }
115 
116   // Indicates if the queue is above the watermark limit, which is a certain
117   // percentage of its size.
is_above_watermark()118   bool is_above_watermark() const { return queued_bytes_ >= watermark_bytes_; }
119 
120   // Returns the watermark limit, in bytes.
watermark_bytes()121   size_t watermark_bytes() const { return watermark_bytes_; }
122 
123   HandoverReadinessStatus GetHandoverReadiness() const;
124 
125   void AddHandoverState(DcSctpSocketHandoverState& state);
126   void RestoreFromState(const DcSctpSocketHandoverState& state);
127 
128  private:
129   bool IsConsistent() const;
130   void AddReassembledMessage(rtc::ArrayView<const UnwrappedTSN> tsns,
131                              DcSctpMessage message);
132   void MaybeMoveLastAssembledWatermarkFurther();
133 
134   struct DeferredResetStreams {
DeferredResetStreamsDeferredResetStreams135     explicit DeferredResetStreams(OutgoingSSNResetRequestParameter req)
136         : req(std::move(req)) {}
137     OutgoingSSNResetRequestParameter req;
138     std::vector<std::pair<TSN, Data>> deferred_chunks;
139   };
140 
141   const std::string log_prefix_;
142   const size_t max_size_bytes_;
143   const size_t watermark_bytes_;
144   UnwrappedTSN::Unwrapper tsn_unwrapper_;
145 
146   // Whenever a message has been assembled, either increase
147   // `last_assembled_tsn_watermark_` or - if there are gaps - add the message's
148   // TSNs into delivered_tsns_ so that messages are not re-delivered on
149   // duplicate chunks.
150   UnwrappedTSN last_assembled_tsn_watermark_;
151   std::set<UnwrappedTSN> delivered_tsns_;
152   // Messages that have been reassembled, and will be returned by
153   // `FlushMessages`.
154   std::vector<DcSctpMessage> reassembled_messages_;
155 
156   // If present, "deferred reset processing" mode is active.
157   absl::optional<DeferredResetStreams> deferred_reset_streams_;
158 
159   // Contains the last request sequence number of the
160   // OutgoingSSNResetRequestParameter that was performed.
161   ReconfigRequestSN last_completed_reset_req_seq_nbr_;
162 
163   // The number of "payload bytes" that are in this queue, in total.
164   size_t queued_bytes_ = 0;
165 
166   // The actual implementation of ReassemblyStreams.
167   std::unique_ptr<ReassemblyStreams> streams_;
168 };
169 }  // namespace dcsctp
170 
171 #endif  // NET_DCSCTP_RX_REASSEMBLY_QUEUE_H_
172