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