Project import generated by Copybara.

PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/quic_buffered_packet_store.h b/quic/core/quic_buffered_packet_store.h
new file mode 100644
index 0000000..f2490ee
--- /dev/null
+++ b/quic/core/quic_buffered_packet_store.h
@@ -0,0 +1,178 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_CORE_QUIC_BUFFERED_PACKET_STORE_H_
+#define QUICHE_QUIC_CORE_QUIC_BUFFERED_PACKET_STORE_H_
+
+#include <list>
+
+#include "net/third_party/quiche/src/quic/core/quic_alarm.h"
+#include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h"
+#include "net/third_party/quiche/src/quic/core/quic_packets.h"
+#include "net/third_party/quiche/src/quic/core/quic_time.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_clock.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_containers.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_export.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_string.h"
+
+namespace quic {
+
+namespace test {
+class QuicBufferedPacketStorePeer;
+}  // namespace test
+
+// This class buffers packets for each connection until either
+// 1) They are requested to be delivered via
+//    DeliverPacket()/DeliverPacketsForNextConnection(), or
+// 2) They expire after exceeding their lifetime in the store.
+//
+// It can only buffer packets on certain number of connections. It has two pools
+// of connections: connections with CHLO buffered and those without CHLO. The
+// latter has its own upper limit along with the max number of connections this
+// store can hold. The former pool can grow till this store is full.
+class QUIC_EXPORT_PRIVATE QuicBufferedPacketStore {
+ public:
+  enum EnqueuePacketResult {
+    SUCCESS = 0,
+    TOO_MANY_PACKETS,  // Too many packets stored up for a certain connection.
+    TOO_MANY_CONNECTIONS  // Too many connections stored up in the store.
+  };
+
+  struct QUIC_EXPORT_PRIVATE BufferedPacket {
+    BufferedPacket(std::unique_ptr<QuicReceivedPacket> packet,
+                   QuicSocketAddress self_address,
+                   QuicSocketAddress peer_address);
+    BufferedPacket(BufferedPacket&& other);
+
+    BufferedPacket& operator=(BufferedPacket&& other);
+
+    ~BufferedPacket();
+
+    std::unique_ptr<QuicReceivedPacket> packet;
+    QuicSocketAddress self_address;
+    QuicSocketAddress peer_address;
+  };
+
+  // A queue of BufferedPackets for a connection.
+  struct QUIC_EXPORT_PRIVATE BufferedPacketList {
+    BufferedPacketList();
+    BufferedPacketList(BufferedPacketList&& other);
+
+    BufferedPacketList& operator=(BufferedPacketList&& other);
+
+    ~BufferedPacketList();
+
+    std::list<BufferedPacket> buffered_packets;
+    QuicTime creation_time;
+    // The alpn from the CHLO, if one was found.
+    QuicString alpn;
+    // Indicating whether this is an IETF QUIC connection.
+    bool ietf_quic;
+    // If buffered_packets contains the CHLO, it is the version of the CHLO.
+    // Otherwise, it is the version of the first packet in |buffered_packets|.
+    ParsedQuicVersion version;
+  };
+
+  typedef QuicLinkedHashMap<QuicConnectionId,
+                            BufferedPacketList,
+                            QuicConnectionIdHash>
+      BufferedPacketMap;
+
+  class QUIC_EXPORT_PRIVATE VisitorInterface {
+   public:
+    virtual ~VisitorInterface() {}
+
+    // Called for each expired connection when alarm fires.
+    virtual void OnExpiredPackets(QuicConnectionId connection_id,
+                                  BufferedPacketList early_arrived_packets) = 0;
+  };
+
+  QuicBufferedPacketStore(VisitorInterface* vistor,
+                          const QuicClock* clock,
+                          QuicAlarmFactory* alarm_factory);
+
+  QuicBufferedPacketStore(const QuicBufferedPacketStore&) = delete;
+
+  ~QuicBufferedPacketStore();
+
+  QuicBufferedPacketStore& operator=(const QuicBufferedPacketStore&) = delete;
+
+  // Adds a copy of packet into packet queue for given connection.
+  // TODO(danzh): Consider to split this method to EnqueueChlo() and
+  // EnqueueDataPacket().
+  EnqueuePacketResult EnqueuePacket(QuicConnectionId connection_id,
+                                    bool ietf_quic,
+                                    const QuicReceivedPacket& packet,
+                                    QuicSocketAddress self_address,
+                                    QuicSocketAddress peer_address,
+                                    bool is_chlo,
+                                    const QuicString& alpn,
+                                    const ParsedQuicVersion& version);
+
+  // Returns true if there are any packets buffered for |connection_id|.
+  bool HasBufferedPackets(QuicConnectionId connection_id) const;
+
+  // Returns the list of buffered packets for |connection_id| and removes them
+  // from the store. Returns an empty list if no early arrived packets for this
+  // connection are present.
+  BufferedPacketList DeliverPackets(QuicConnectionId connection_id);
+
+  // Discards packets buffered for |connection_id|, if any.
+  void DiscardPackets(QuicConnectionId connection_id);
+
+  // Examines how long packets have been buffered in the store for each
+  // connection. If they stay too long, removes them for new coming packets and
+  // calls |visitor_|'s OnPotentialConnectionExpire().
+  // Resets the alarm at the end.
+  void OnExpirationTimeout();
+
+  // Delivers buffered packets for next connection with CHLO to open.
+  // Return connection id for next connection in |connection_id|
+  // and all buffered packets including CHLO.
+  // The returned list should at least has one packet(CHLO) if
+  // store does have any connection to open. If no connection in the store has
+  // received CHLO yet, empty list will be returned.
+  BufferedPacketList DeliverPacketsForNextConnection(
+      QuicConnectionId* connection_id);
+
+  // Is given connection already buffered in the store?
+  bool HasChloForConnection(QuicConnectionId connection_id);
+
+  // Is there any CHLO buffered in the store?
+  bool HasChlosBuffered() const;
+
+ private:
+  friend class test::QuicBufferedPacketStorePeer;
+
+  // Set expiration alarm if it hasn't been set.
+  void MaybeSetExpirationAlarm();
+
+  // Return true if add an extra packet will go beyond allowed max connection
+  // limit. The limit for non-CHLO packet and CHLO packet is different.
+  bool ShouldBufferPacket(bool is_chlo);
+
+  // A map to store packet queues with creation time for each connection.
+  BufferedPacketMap undecryptable_packets_;
+
+  // The max time the packets of a connection can be buffer in the store.
+  const QuicTime::Delta connection_life_span_;
+
+  VisitorInterface* visitor_;  // Unowned.
+
+  const QuicClock* clock_;  // Unowned.
+
+  // This alarm fires every |connection_life_span_| to clean up
+  // packets staying in the store for too long.
+  std::unique_ptr<QuicAlarm> expiration_alarm_;
+
+  // Keeps track of connection with CHLO buffered up already and the order they
+  // arrive.
+  QuicLinkedHashMap<QuicConnectionId, bool, QuicConnectionIdHash>
+      connections_with_chlo_;
+};
+
+}  // namespace quic
+
+#endif  // QUICHE_QUIC_CORE_QUIC_BUFFERED_PACKET_STORE_H_