• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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