Index: net/quic/core/quic_buffered_packet_store.cc |
diff --git a/net/quic/core/quic_buffered_packet_store.cc b/net/quic/core/quic_buffered_packet_store.cc |
index 957f53c0d2ab0acc4a8941df017ce98d6492d76d..9024d227245655f02bad39eaff9f2c53683d416f 100644 |
--- a/net/quic/core/quic_buffered_packet_store.cc |
+++ b/net/quic/core/quic_buffered_packet_store.cc |
@@ -7,6 +7,7 @@ |
#include <list> |
#include "base/stl_util.h" |
+#include "net/quic/core/quic_bug_tracker.h" |
using std::list; |
@@ -18,6 +19,9 @@ typedef QuicBufferedPacketStore::BufferedPacketList BufferedPacketList; |
// Max number of connections this store can keep track. |
static const size_t kDefaultMaxConnectionsInStore = 100; |
+// Up to half of the capacity can be used for storing non-CHLO packets. |
+static const size_t kMaxConnectionsWithoutCHLO = |
+ kDefaultMaxConnectionsInStore / 2; |
namespace { |
@@ -78,9 +82,16 @@ EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket( |
QuicConnectionId connection_id, |
const QuicReceivedPacket& packet, |
IPEndPoint server_address, |
- IPEndPoint client_address) { |
- if (!base::ContainsKey(undecryptable_packets_, connection_id) && IsFull()) { |
- // Drop the packet if store can't keep track of more connections. |
+ IPEndPoint client_address, |
+ bool is_chlo) { |
+ QUIC_BUG_IF(is_chlo && |
+ base::ContainsKey(connections_with_chlo_, connection_id)) |
+ << "Shouldn't buffer duplicated CHLO on connection " << connection_id; |
+ |
+ if (!base::ContainsKey(undecryptable_packets_, connection_id) && |
+ ShouldBufferPacket(is_chlo)) { |
+ // Drop the packet if the upper limit of undecryptable packets has been |
+ // reached or the whole capacity of the store has been reached. |
return TOO_MANY_CONNECTIONS; |
} else if (!base::ContainsKey(undecryptable_packets_, connection_id)) { |
undecryptable_packets_.emplace( |
@@ -90,10 +101,18 @@ EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket( |
BufferedPacketList& queue = |
undecryptable_packets_.find(connection_id)->second; |
- if (queue.buffered_packets.size() >= kDefaultMaxUndecryptablePackets) { |
- // If there are kMaxBufferedPacketsPerConnection packets buffered up for |
- // this connection, drop the current packet. |
- return TOO_MANY_PACKETS; |
+ if (!is_chlo) { |
+ // If current packet is not CHLO, it might not be buffered because store |
+ // only buffers certain number of undecryptable packets per connection. |
+ size_t num_non_chlo_packets = |
+ base::ContainsKey(connections_with_chlo_, connection_id) |
+ ? (queue.buffered_packets.size() - 1) |
+ : queue.buffered_packets.size(); |
+ if (num_non_chlo_packets >= kDefaultMaxUndecryptablePackets) { |
+ // If there are kMaxBufferedPacketsPerConnection packets buffered up for |
+ // this connection, drop the current packet. |
+ return TOO_MANY_PACKETS; |
+ } |
} |
if (queue.buffered_packets.empty()) { |
@@ -104,9 +123,15 @@ EnqueuePacketResult QuicBufferedPacketStore::EnqueuePacket( |
BufferedPacket new_entry(std::unique_ptr<QuicReceivedPacket>(packet.Clone()), |
server_address, client_address); |
- |
- queue.buffered_packets.push_back(std::move(new_entry)); |
- |
+ if (is_chlo) { |
+ // Add CHLO to the beginning of buffered packets so that it can be delivered |
+ // first later. |
+ queue.buffered_packets.push_front(std::move(new_entry)); |
+ connections_with_chlo_[connection_id] = false; // Dummy value. |
+ } else { |
+ // Buffer non-CHLO packets in arrival order. |
+ queue.buffered_packets.push_back(std::move(new_entry)); |
+ } |
MaybeSetExpirationAlarm(); |
return SUCCESS; |
} |
@@ -116,6 +141,10 @@ bool QuicBufferedPacketStore::HasBufferedPackets( |
return base::ContainsKey(undecryptable_packets_, connection_id); |
} |
+bool QuicBufferedPacketStore::HasChlosBuffered() const { |
+ return !connections_with_chlo_.empty(); |
+} |
+ |
list<BufferedPacket> QuicBufferedPacketStore::DeliverPackets( |
QuicConnectionId connection_id) { |
list<BufferedPacket> packets_to_deliver; |
@@ -134,8 +163,10 @@ void QuicBufferedPacketStore::OnExpirationTimeout() { |
if (entry.second.creation_time > expiration_time) { |
break; |
} |
- visitor_->OnExpiredPackets(entry.first, std::move(entry.second)); |
+ QuicConnectionId connection_id = entry.first; |
+ visitor_->OnExpiredPackets(connection_id, std::move(entry.second)); |
undecryptable_packets_.erase(undecryptable_packets_.begin()); |
+ connections_with_chlo_.erase(connection_id); |
} |
if (!undecryptable_packets_.empty()) { |
expiration_alarm_->Set(clock_->ApproximateNow() + connection_life_span_); |
@@ -148,8 +179,40 @@ void QuicBufferedPacketStore::MaybeSetExpirationAlarm() { |
} |
} |
-bool QuicBufferedPacketStore::IsFull() { |
- return undecryptable_packets_.size() >= kDefaultMaxConnectionsInStore; |
+bool QuicBufferedPacketStore::ShouldBufferPacket(bool is_chlo) { |
+ bool is_store_full = |
+ undecryptable_packets_.size() >= kDefaultMaxConnectionsInStore; |
+ |
+ if (is_chlo) { |
+ return is_store_full; |
+ } |
+ |
+ size_t num_connections_without_chlo = |
+ undecryptable_packets_.size() - connections_with_chlo_.size(); |
+ bool reach_non_chlo_limit = |
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop && |
+ num_connections_without_chlo >= kMaxConnectionsWithoutCHLO; |
+ |
+ return is_store_full || reach_non_chlo_limit; |
+} |
+ |
+list<BufferedPacket> QuicBufferedPacketStore::DeliverPacketsForNextConnection( |
+ QuicConnectionId* connection_id) { |
+ if (connections_with_chlo_.empty()) { |
+ // Returns empty list if no CHLO has been buffered. |
+ return list<BufferedPacket>(); |
+ } |
+ *connection_id = connections_with_chlo_.front().first; |
+ connections_with_chlo_.erase(connections_with_chlo_.begin()); |
+ |
+ list<BufferedPacket> packets = DeliverPackets(*connection_id); |
+ DCHECK(!packets.empty()) << "Try to deliver connectons without CHLO"; |
+ return packets; |
+} |
+ |
+bool QuicBufferedPacketStore::HasChloForConnection( |
+ QuicConnectionId connection_id) { |
+ return base::ContainsKey(connections_with_chlo_, connection_id); |
} |
} // namespace net |