Index: net/quic/core/quic_buffered_packet_store_test.cc |
diff --git a/net/quic/core/quic_buffered_packet_store_test.cc b/net/quic/core/quic_buffered_packet_store_test.cc |
index 53cbe0c132d78e9209c05c784ed7510129303f4d..9bce74c45f0d52a190653c41147f3a55eaac04db 100644 |
--- a/net/quic/core/quic_buffered_packet_store_test.cc |
+++ b/net/quic/core/quic_buffered_packet_store_test.cc |
@@ -23,6 +23,8 @@ typedef QuicBufferedPacketStore::BufferedPacket BufferedPacket; |
typedef QuicBufferedPacketStore::EnqueuePacketResult EnqueuePacketResult; |
static const size_t kDefaultMaxConnectionsInStore = 100; |
+static const size_t kMaxConnectionsWithoutCHLO = |
+ kDefaultMaxConnectionsInStore / 2; |
namespace test { |
namespace { |
@@ -70,8 +72,8 @@ class QuicBufferedPacketStoreTest : public ::testing::Test { |
TEST_F(QuicBufferedPacketStoreTest, SimpleEnqueueAndDeliverPacket) { |
QuicConnectionId connection_id = 1; |
- store_.EnqueuePacket(connection_id, packet_, server_address_, |
- client_address_); |
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, |
+ false); |
EXPECT_TRUE(store_.HasBufferedPackets(connection_id)); |
list<BufferedPacket> queue = store_.DeliverPackets(connection_id); |
ASSERT_EQ(1u, queue.size()); |
@@ -88,10 +90,10 @@ TEST_F(QuicBufferedPacketStoreTest, SimpleEnqueueAndDeliverPacket) { |
TEST_F(QuicBufferedPacketStoreTest, DifferentPacketAddressOnOneConnection) { |
IPEndPoint addr_with_new_port(Loopback4(), 256); |
QuicConnectionId connection_id = 1; |
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, |
+ false); |
store_.EnqueuePacket(connection_id, packet_, server_address_, |
- client_address_); |
- store_.EnqueuePacket(connection_id, packet_, server_address_, |
- addr_with_new_port); |
+ addr_with_new_port, false); |
list<BufferedPacket> queue = store_.DeliverPackets(connection_id); |
ASSERT_EQ(2u, queue.size()); |
// The address migration path should be preserved. |
@@ -105,9 +107,9 @@ TEST_F(QuicBufferedPacketStoreTest, |
for (QuicConnectionId connection_id = 1; connection_id <= num_connections; |
++connection_id) { |
store_.EnqueuePacket(connection_id, packet_, server_address_, |
- client_address_); |
+ client_address_, false); |
store_.EnqueuePacket(connection_id, packet_, server_address_, |
- client_address_); |
+ client_address_, false); |
} |
// Deliver packets in reversed order. |
@@ -124,10 +126,17 @@ TEST_F(QuicBufferedPacketStoreTest, |
// buffered. |
size_t num_packets = kDefaultMaxUndecryptablePackets + 1; |
QuicConnectionId connection_id = 1; |
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop) { |
+ // Arrived CHLO packet shouldn't affect how many non-CHLO pacekts store can |
+ // keep. |
+ EXPECT_EQ(QuicBufferedPacketStore::SUCCESS, |
+ store_.EnqueuePacket(connection_id, packet_, server_address_, |
+ client_address_, true)); |
+ } |
for (size_t i = 1; i <= num_packets; ++i) { |
// Only first |kDefaultMaxUndecryptablePackets packets| will be buffered. |
EnqueuePacketResult result = store_.EnqueuePacket( |
- connection_id, packet_, server_address_, client_address_); |
+ connection_id, packet_, server_address_, client_address_, false); |
if (i <= kDefaultMaxUndecryptablePackets) { |
EXPECT_EQ(EnqueuePacketResult::SUCCESS, result); |
} else { |
@@ -135,32 +144,40 @@ TEST_F(QuicBufferedPacketStoreTest, |
} |
} |
- // Only first |kDefaultMaxUndecryptablePackets| packets are kept in the store |
- // and can be delivered. |
- EXPECT_EQ(kDefaultMaxUndecryptablePackets, |
+ // Only first |kDefaultMaxUndecryptablePackets| non-CHLO packets and CHLO are |
+ // buffered. |
+ EXPECT_EQ(kDefaultMaxUndecryptablePackets + |
+ (FLAGS_quic_limit_num_new_sessions_per_epoll_loop ? 1 : 0), |
store_.DeliverPackets(connection_id).size()); |
} |
-TEST_F(QuicBufferedPacketStoreTest, FailToBufferPacketsForTooManyConnections) { |
+TEST_F(QuicBufferedPacketStoreTest, ReachNonChloConnectionUpperLimit) { |
// Tests that store can only keep early arrived packets for limited number of |
// connections. |
- size_t num_connections = kDefaultMaxConnectionsInStore + 1; |
- for (size_t connection_id = 1; connection_id <= num_connections; |
+ const size_t kNumConnections = |
+ (FLAGS_quic_limit_num_new_sessions_per_epoll_loop |
+ ? kMaxConnectionsWithoutCHLO |
+ : kDefaultMaxConnectionsInStore) + |
+ 1; |
+ for (size_t connection_id = 1; connection_id <= kNumConnections; |
++connection_id) { |
EnqueuePacketResult result = store_.EnqueuePacket( |
- connection_id, packet_, server_address_, client_address_); |
- if (connection_id <= kDefaultMaxConnectionsInStore) { |
+ connection_id, packet_, server_address_, client_address_, false); |
+ if (connection_id <= (FLAGS_quic_limit_num_new_sessions_per_epoll_loop |
+ ? kMaxConnectionsWithoutCHLO |
+ : kDefaultMaxConnectionsInStore)) { |
EXPECT_EQ(EnqueuePacketResult::SUCCESS, result); |
} else { |
EXPECT_EQ(EnqueuePacketResult::TOO_MANY_CONNECTIONS, result); |
} |
} |
- // Store only keeps early arrived packets upto |kDefaultMaxConnectionsInStore| |
- // connections. |
- for (size_t connection_id = 1; connection_id <= num_connections; |
+ // Store only keeps early arrived packets upto |kNumConnections| connections. |
+ for (size_t connection_id = 1; connection_id <= kNumConnections; |
++connection_id) { |
list<BufferedPacket> queue = store_.DeliverPackets(connection_id); |
- if (connection_id <= kDefaultMaxConnectionsInStore) { |
+ if (connection_id <= (FLAGS_quic_limit_num_new_sessions_per_epoll_loop |
+ ? kMaxConnectionsWithoutCHLO |
+ : kDefaultMaxConnectionsInStore)) { |
EXPECT_EQ(1u, queue.size()); |
} else { |
EXPECT_EQ(0u, queue.size()); |
@@ -168,10 +185,91 @@ TEST_F(QuicBufferedPacketStoreTest, FailToBufferPacketsForTooManyConnections) { |
} |
} |
-TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) { |
+TEST_F(QuicBufferedPacketStoreTest, |
+ FullStoreFailToBufferDataPacketOnNewConnection) { |
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true; |
+ // Send enough CHLOs so that store gets full before number of connections |
+ // without CHLO reaches its upper limit. |
+ size_t num_chlos = |
+ kDefaultMaxConnectionsInStore - kMaxConnectionsWithoutCHLO + 1; |
+ for (size_t connection_id = 1; connection_id <= num_chlos; ++connection_id) { |
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS, |
+ store_.EnqueuePacket(connection_id, packet_, server_address_, |
+ client_address_, true)); |
+ } |
+ |
+ // Send data packets on another |kMaxConnectionsWithoutCHLO| connections. |
+ // Store should only be able to buffer till it's full. |
+ for (size_t conn_id = num_chlos + 1; |
+ conn_id <= (kDefaultMaxConnectionsInStore + 1); ++conn_id) { |
+ EnqueuePacketResult result = store_.EnqueuePacket( |
+ conn_id, packet_, server_address_, client_address_, true); |
+ if (conn_id <= kDefaultMaxConnectionsInStore) { |
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS, result); |
+ } else { |
+ EXPECT_EQ(EnqueuePacketResult::TOO_MANY_CONNECTIONS, result); |
+ } |
+ } |
+} |
+ |
+TEST_F(QuicBufferedPacketStoreTest, EnqueueChloOnTooManyDifferentConnections) { |
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true; |
+ // Buffer data packets on different connections upto limit. |
+ for (QuicConnectionId conn_id = 1; conn_id <= kMaxConnectionsWithoutCHLO; |
+ ++conn_id) { |
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS, |
+ store_.EnqueuePacket(conn_id, packet_, server_address_, |
+ client_address_, false)); |
+ } |
+ |
+ // Buffer CHLOs on other connections till store is full. |
+ for (size_t i = kMaxConnectionsWithoutCHLO + 1; |
+ i <= kDefaultMaxConnectionsInStore + 1; ++i) { |
+ EnqueuePacketResult rs = store_.EnqueuePacket( |
+ /*connection_id=*/i, packet_, server_address_, client_address_, true); |
+ if (i <= kDefaultMaxConnectionsInStore) { |
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS, rs); |
+ EXPECT_TRUE(store_.HasChloForConnection(/*connection_id=*/i)); |
+ } else { |
+ // Last CHLO can't be buffered because store is full. |
+ EXPECT_EQ(EnqueuePacketResult::TOO_MANY_CONNECTIONS, rs); |
+ EXPECT_FALSE(store_.HasChloForConnection(/*connection_id=*/i)); |
+ } |
+ } |
+ |
+ // But buffering a CHLO belonging to a connection already has data packet |
+ // buffered in the store should success. This is the connection should be |
+ // delivered at last. |
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS, |
+ store_.EnqueuePacket(/*connection_id=*/1, packet_, server_address_, |
+ client_address_, true)); |
+ EXPECT_TRUE(store_.HasChloForConnection(/*connection_id=*/1)); |
+ |
+ QuicConnectionId delivered_conn_id; |
+ for (size_t i = 0; |
+ i < kDefaultMaxConnectionsInStore - kMaxConnectionsWithoutCHLO + 1; |
+ ++i) { |
+ if (i < kDefaultMaxConnectionsInStore - kMaxConnectionsWithoutCHLO) { |
+ // Only CHLO is buffered. |
+ EXPECT_EQ( |
+ 1u, |
+ store_.DeliverPacketsForNextConnection(&delivered_conn_id).size()); |
+ EXPECT_EQ(i + kMaxConnectionsWithoutCHLO + 1, delivered_conn_id); |
+ } else { |
+ EXPECT_EQ( |
+ 2u, |
+ store_.DeliverPacketsForNextConnection(&delivered_conn_id).size()); |
+ EXPECT_EQ(1u, delivered_conn_id); |
+ } |
+ } |
+ EXPECT_FALSE(store_.HasChlosBuffered()); |
+} |
+ |
+TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery1) { |
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = false; |
QuicConnectionId connection_id = 1; |
- store_.EnqueuePacket(connection_id, packet_, server_address_, |
- client_address_); |
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, |
+ false); |
// Packet for another connection arrive 1ms later. |
clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); |
QuicConnectionId connection_id2 = 2; |
@@ -179,7 +277,7 @@ TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) { |
// connections. |
IPEndPoint another_client_address(Loopback4(), 255); |
store_.EnqueuePacket(connection_id2, packet_, server_address_, |
- another_client_address); |
+ another_client_address, false); |
// Advance clock to the time when connection 1 expires. |
clock_.AdvanceTime( |
QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() - |
@@ -205,9 +303,76 @@ TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery) { |
// for them to expire. |
QuicConnectionId connection_id3 = 3; |
store_.EnqueuePacket(connection_id3, packet_, server_address_, |
- client_address_); |
+ client_address_, false); |
store_.EnqueuePacket(connection_id3, packet_, server_address_, |
- client_address_); |
+ client_address_, false); |
+ clock_.AdvanceTime( |
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() - |
+ clock_.ApproximateNow()); |
+ alarm_factory_.FireAlarm( |
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_)); |
+ // |last_expired_packet_queue_| should be updated. |
+ EXPECT_EQ(2u, visitor_.last_expired_packet_queue_.buffered_packets.size()); |
+} |
+ |
+// Tests that store expires long-staying connections appropriately for |
+// connections both with and without CHLOs. |
+TEST_F(QuicBufferedPacketStoreTest, PacketQueueExpiredBeforeDelivery2) { |
+ FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true; |
+ QuicConnectionId connection_id = 1; |
+ store_.EnqueuePacket(connection_id, packet_, server_address_, client_address_, |
+ false); |
+ if (FLAGS_quic_limit_num_new_sessions_per_epoll_loop) { |
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS, |
+ store_.EnqueuePacket(connection_id, packet_, server_address_, |
+ client_address_, true)); |
+ } |
+ QuicConnectionId connection_id2 = 2; |
+ EXPECT_EQ(EnqueuePacketResult::SUCCESS, |
+ store_.EnqueuePacket(connection_id2, packet_, server_address_, |
+ client_address_, false)); |
+ |
+ // CHLO on connection 3 arrives 1ms later. |
+ clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(1)); |
+ QuicConnectionId connection_id3 = 3; |
+ // Use different client address to differetiate packets from different |
+ // connections. |
+ IPEndPoint another_client_address(Any4(), 255); |
+ store_.EnqueuePacket(connection_id3, packet_, server_address_, |
+ another_client_address, true); |
+ |
+ // Advance clock to the time when connection 1 and 2 expires. |
+ clock_.AdvanceTime( |
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() - |
+ clock_.ApproximateNow()); |
+ ASSERT_GE(clock_.ApproximateNow(), |
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline()); |
+ // Fire alarm to remove long-staying connection 1 and 2 packets. |
+ alarm_factory_.FireAlarm( |
+ QuicBufferedPacketStorePeer::expiration_alarm(&store_)); |
+ EXPECT_EQ(1u, visitor_.last_expired_packet_queue_.buffered_packets.size()); |
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id)); |
+ EXPECT_FALSE(store_.HasBufferedPackets(connection_id2)); |
+ |
+ // Try to deliver packets, but packet queue has been removed so no |
+ // packets can be returned. |
+ ASSERT_EQ(0u, store_.DeliverPackets(connection_id).size()); |
+ ASSERT_EQ(0u, store_.DeliverPackets(connection_id2).size()); |
+ QuicConnectionId delivered_conn_id; |
+ auto queue = store_.DeliverPacketsForNextConnection(&delivered_conn_id); |
+ // Connection 3 is the next to be delivered as connection 1 already expired. |
+ EXPECT_EQ(connection_id3, delivered_conn_id); |
+ ASSERT_EQ(1u, queue.size()); |
+ // Packets in connection 3 should use another client address. |
+ EXPECT_EQ(another_client_address, queue.front().client_address); |
+ |
+ // Test the alarm is reset by enqueueing 2 packets for 4th connection and wait |
+ // for them to expire. |
+ QuicConnectionId connection_id4 = 4; |
+ store_.EnqueuePacket(connection_id4, packet_, server_address_, |
+ client_address_, false); |
+ store_.EnqueuePacket(connection_id4, packet_, server_address_, |
+ client_address_, false); |
clock_.AdvanceTime( |
QuicBufferedPacketStorePeer::expiration_alarm(&store_)->deadline() - |
clock_.ApproximateNow()); |