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