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