xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_buffered_packet_store.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef QUICHE_QUIC_CORE_QUIC_BUFFERED_PACKET_STORE_H_
6 #define QUICHE_QUIC_CORE_QUIC_BUFFERED_PACKET_STORE_H_
7 
8 #include <cstdint>
9 #include <list>
10 #include <memory>
11 #include <optional>
12 #include <string>
13 #include <vector>
14 
15 #include "quiche/quic/core/connection_id_generator.h"
16 #include "quiche/quic/core/quic_alarm.h"
17 #include "quiche/quic/core/quic_alarm_factory.h"
18 #include "quiche/quic/core/quic_clock.h"
19 #include "quiche/quic/core/quic_connection_id.h"
20 #include "quiche/quic/core/quic_packets.h"
21 #include "quiche/quic/core/quic_time.h"
22 #include "quiche/quic/core/quic_types.h"
23 #include "quiche/quic/core/quic_versions.h"
24 #include "quiche/quic/core/tls_chlo_extractor.h"
25 #include "quiche/quic/platform/api/quic_export.h"
26 #include "quiche/quic/platform/api/quic_socket_address.h"
27 #include "quiche/common/quiche_linked_hash_map.h"
28 
29 namespace quic {
30 
31 namespace test {
32 class QuicBufferedPacketStorePeer;
33 }  // namespace test
34 
35 // This class buffers packets for each connection until either
36 // 1) They are requested to be delivered via
37 //    DeliverPacket()/DeliverPacketsForNextConnection(), or
38 // 2) They expire after exceeding their lifetime in the store.
39 //
40 // It can only buffer packets on certain number of connections. It has two pools
41 // of connections: connections with CHLO buffered and those without CHLO. The
42 // latter has its own upper limit along with the max number of connections this
43 // store can hold. The former pool can grow till this store is full.
44 class QUICHE_EXPORT QuicBufferedPacketStore {
45  public:
46   enum EnqueuePacketResult {
47     SUCCESS = 0,
48     TOO_MANY_PACKETS,  // Too many packets stored up for a certain connection.
49     TOO_MANY_CONNECTIONS  // Too many connections stored up in the store.
50   };
51 
52   struct QUICHE_EXPORT BufferedPacket {
53     BufferedPacket(std::unique_ptr<QuicReceivedPacket> packet,
54                    QuicSocketAddress self_address,
55                    QuicSocketAddress peer_address);
56     BufferedPacket(BufferedPacket&& other);
57 
58     BufferedPacket& operator=(BufferedPacket&& other);
59 
60     ~BufferedPacket();
61 
62     std::unique_ptr<QuicReceivedPacket> packet;
63     QuicSocketAddress self_address;
64     QuicSocketAddress peer_address;
65   };
66 
67   // A queue of BufferedPackets for a connection.
68   struct QUICHE_EXPORT BufferedPacketList {
69     BufferedPacketList();
70     BufferedPacketList(BufferedPacketList&& other);
71 
72     BufferedPacketList& operator=(BufferedPacketList&& other);
73 
74     ~BufferedPacketList();
75 
76     std::list<BufferedPacket> buffered_packets;
77     QuicTime creation_time;
78     // |parsed_chlo| is set iff the entire CHLO has been received.
79     std::optional<ParsedClientHello> parsed_chlo;
80     // Indicating whether this is an IETF QUIC connection.
81     bool ietf_quic;
82     // If buffered_packets contains the CHLO, it is the version of the CHLO.
83     // Otherwise, it is the version of the first packet in |buffered_packets|.
84     ParsedQuicVersion version;
85     TlsChloExtractor tls_chlo_extractor;
86     // Only one reference to the generator is stored per connection, and this is
87     // stored when the CHLO is buffered. The connection needs a stable,
88     // consistent way to generate IDs. Fixing it on the CHLO is a
89     // straightforward way to enforce that.
90     ConnectionIdGeneratorInterface* connection_id_generator = nullptr;
91   };
92 
93   using BufferedPacketMap =
94       quiche::QuicheLinkedHashMap<QuicConnectionId, BufferedPacketList,
95                                   QuicConnectionIdHash>;
96 
97   class QUICHE_EXPORT VisitorInterface {
98    public:
~VisitorInterface()99     virtual ~VisitorInterface() {}
100 
101     // Called for each expired connection when alarm fires.
102     virtual void OnExpiredPackets(QuicConnectionId connection_id,
103                                   BufferedPacketList early_arrived_packets) = 0;
104   };
105 
106   QuicBufferedPacketStore(VisitorInterface* visitor, const QuicClock* clock,
107                           QuicAlarmFactory* alarm_factory);
108 
109   QuicBufferedPacketStore(const QuicBufferedPacketStore&) = delete;
110 
111   ~QuicBufferedPacketStore();
112 
113   QuicBufferedPacketStore& operator=(const QuicBufferedPacketStore&) = delete;
114 
115   // Adds a copy of packet into the packet queue for given connection. If the
116   // packet is the last one of the CHLO, |parsed_chlo| will contain a parsed
117   // version of the CHLO. |connection_id_generator| is the Connection ID
118   // Generator to use with the connection. It is ignored if |parsed_chlo| is
119   // absent.
120   EnqueuePacketResult EnqueuePacket(
121       QuicConnectionId connection_id, bool ietf_quic,
122       const QuicReceivedPacket& packet, QuicSocketAddress self_address,
123       QuicSocketAddress peer_address, const ParsedQuicVersion& version,
124       std::optional<ParsedClientHello> parsed_chlo,
125       ConnectionIdGeneratorInterface* connection_id_generator);
126 
127   // Returns true if there are any packets buffered for |connection_id|.
128   bool HasBufferedPackets(QuicConnectionId connection_id) const;
129 
130   // Ingests this packet into the corresponding TlsChloExtractor. This should
131   // only be called when HasBufferedPackets(connection_id) is true.
132   // Returns whether we've now parsed a full multi-packet TLS CHLO.
133   // When this returns true, |out_supported_groups| is populated with the list
134   // of groups in the CHLO's 'supported_groups' TLS extension. |out_alpns| is
135   // populated with the list of ALPNs extracted from the CHLO. |out_sni| is
136   // populated with the SNI tag in CHLO. |out_resumption_attempted| is populated
137   // if the CHLO has the 'pre_shared_key' TLS extension.
138   // |out_early_data_attempted| is populated if the CHLO has the 'early_data'
139   // TLS extension. When this returns false, and an unrecoverable error happened
140   // due to a TLS alert, |*tls_alert| will be set to the alert value.
141   bool IngestPacketForTlsChloExtraction(
142       const QuicConnectionId& connection_id, const ParsedQuicVersion& version,
143       const QuicReceivedPacket& packet,
144       std::vector<uint16_t>* out_supported_groups,
145       std::vector<std::string>* out_alpns, std::string* out_sni,
146       bool* out_resumption_attempted, bool* out_early_data_attempted,
147       std::optional<uint8_t>* tls_alert);
148 
149   // Returns the list of buffered packets for |connection_id| and removes them
150   // from the store. Returns an empty list if no early arrived packets for this
151   // connection are present.
152   BufferedPacketList DeliverPackets(QuicConnectionId connection_id);
153 
154   // Discards packets buffered for |connection_id|, if any.
155   void DiscardPackets(QuicConnectionId connection_id);
156 
157   // Discards all the packets.
158   void DiscardAllPackets();
159 
160   // Examines how long packets have been buffered in the store for each
161   // connection. If they stay too long, removes them for new coming packets and
162   // calls |visitor_|'s OnPotentialConnectionExpire().
163   // Resets the alarm at the end.
164   void OnExpirationTimeout();
165 
166   // Delivers buffered packets for next connection with CHLO to open.
167   // Return connection id for next connection in |connection_id|
168   // and all buffered packets including CHLO.
169   // The returned list should at least has one packet(CHLO) if
170   // store does have any connection to open. If no connection in the store has
171   // received CHLO yet, empty list will be returned.
172   BufferedPacketList DeliverPacketsForNextConnection(
173       QuicConnectionId* connection_id);
174 
175   // Is given connection already buffered in the store?
176   bool HasChloForConnection(QuicConnectionId connection_id);
177 
178   // Is there any CHLO buffered in the store?
179   bool HasChlosBuffered() const;
180 
181  private:
182   friend class test::QuicBufferedPacketStorePeer;
183 
184   // Set expiration alarm if it hasn't been set.
185   void MaybeSetExpirationAlarm();
186 
187   // Return true if add an extra packet will go beyond allowed max connection
188   // limit. The limit for non-CHLO packet and CHLO packet is different.
189   bool ShouldNotBufferPacket(bool is_chlo);
190 
191   // A map to store packet queues with creation time for each connection.
192   BufferedPacketMap undecryptable_packets_;
193 
194   // The max time the packets of a connection can be buffer in the store.
195   const QuicTime::Delta connection_life_span_;
196 
197   VisitorInterface* visitor_;  // Unowned.
198 
199   const QuicClock* clock_;  // Unowned.
200 
201   // This alarm fires every |connection_life_span_| to clean up
202   // packets staying in the store for too long.
203   std::unique_ptr<QuicAlarm> expiration_alarm_;
204 
205   // Keeps track of connection with CHLO buffered up already and the order they
206   // arrive.
207   quiche::QuicheLinkedHashMap<QuicConnectionId, bool, QuicConnectionIdHash>
208       connections_with_chlo_;
209 };
210 
211 }  // namespace quic
212 
213 #endif  // QUICHE_QUIC_CORE_QUIC_BUFFERED_PACKET_STORE_H_
214