| Index: net/tools/quic/quic_dispatcher_test.cc
|
| diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
|
| index 8875ee7ca949758348e83902cdad19885c2ff97d..bdd3f6af440081869d803fe20dd1a664c8721ca1 100644
|
| --- a/net/tools/quic/quic_dispatcher_test.cc
|
| +++ b/net/tools/quic/quic_dispatcher_test.cc
|
| @@ -52,6 +52,9 @@ using testing::WithoutArgs;
|
| using testing::_;
|
|
|
| static const size_t kDefaultMaxConnectionsInStore = 100;
|
| +static const size_t kMaxConnectionsWithoutCHLO =
|
| + kDefaultMaxConnectionsInStore / 2;
|
| +static const int16_t kMaxNumSessionsToCreate = 16;
|
|
|
| namespace net {
|
| namespace test {
|
| @@ -176,6 +179,9 @@ class QuicDispatcherTest : public ::testing::Test {
|
|
|
| void SetUp() override {
|
| dispatcher_->InitializeWithWriter(new QuicDefaultPacketWriter(1));
|
| + // Set the counter to some value to start with.
|
| + QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop(
|
| + dispatcher_.get(), kMaxNumSessionsToCreate);
|
| }
|
|
|
| ~QuicDispatcherTest() override {}
|
| @@ -1160,10 +1166,14 @@ TEST_P(BufferedPacketStoreTest,
|
| InSequence s;
|
| server_address_ = IPEndPoint(Any4(), 5);
|
| // A bunch of non-CHLO should be buffered upon arrival.
|
| - for (size_t i = 1; i <= kDefaultMaxConnectionsInStore + 1; ++i) {
|
| + size_t kNumConnections = (FLAGS_quic_limit_num_new_sessions_per_epoll_loop
|
| + ? kMaxConnectionsWithoutCHLO
|
| + : kDefaultMaxConnectionsInStore) +
|
| + 1;
|
| + for (size_t i = 1; i <= kNumConnections; ++i) {
|
| IPEndPoint client_address(Loopback4(), i);
|
| QuicConnectionId conn_id = i;
|
| - if (i <= kDefaultMaxConnectionsInStore) {
|
| + if (i <= kNumConnections - 1) {
|
| // As they are on different connection, they should trigger
|
| // OnNewConnectionAdded(). The last packet should be dropped.
|
| EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id));
|
| @@ -1177,10 +1187,14 @@ TEST_P(BufferedPacketStoreTest,
|
|
|
| // Pop out the packet on last connection as it shouldn't be enqueued in store
|
| // as well.
|
| - data_connection_map_[kDefaultMaxConnectionsInStore + 1].pop_front();
|
| -
|
| - // Process CHLOs.
|
| - for (size_t i = 1; i <= kDefaultMaxConnectionsInStore + 1; ++i) {
|
| + data_connection_map_[kNumConnections].pop_front();
|
| +
|
| + // Reset session creation counter to ensure processing CHLO can always
|
| + // create session.
|
| + QuicDispatcherPeer::set_new_sessions_allowed_per_event_loop(dispatcher_.get(),
|
| + kNumConnections);
|
| + // Process CHLOs to create session for these connections.
|
| + for (size_t i = 1; i <= kNumConnections; ++i) {
|
| IPEndPoint client_address(Loopback4(), i);
|
| QuicConnectionId conn_id = i;
|
| EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_address))
|
| @@ -1188,22 +1202,23 @@ TEST_P(BufferedPacketStoreTest,
|
| dispatcher_.get(), config_, conn_id, client_address, &mock_helper_,
|
| &mock_alarm_factory_, &crypto_config_,
|
| QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
|
| - if (conn_id == kDefaultMaxConnectionsInStore + 1) {
|
| + if (conn_id == kNumConnections) {
|
| // The last CHLO should trigger OnNewConnectionAdded() since it's the
|
| // first packet arrives on that connection.
|
| EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id));
|
| }
|
| - // First |kDefaultMaxConnectionsInStore| connections should have buffered
|
| + // First |kNumConnections| - 1 connections should have buffered
|
| // a packet in store. The rest should have been dropped.
|
| - if (i <= kDefaultMaxConnectionsInStore) {
|
| - EXPECT_CALL(
|
| - *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
|
| - ProcessUdpPacket(_, client_address, _))
|
| - .Times(2)
|
| - .WillRepeatedly(testing::WithArg<2>(
|
| - Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
|
| - base::Unretained(this), conn_id))));
|
| - }
|
| + size_t upper_limit = FLAGS_quic_limit_num_new_sessions_per_epoll_loop
|
| + ? kMaxConnectionsWithoutCHLO
|
| + : kDefaultMaxConnectionsInStore;
|
| + size_t num_packet_to_process = i <= upper_limit ? 2u : 1u;
|
| + EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
|
| + ProcessUdpPacket(_, client_address, _))
|
| + .Times(num_packet_to_process)
|
| + .WillRepeatedly(testing::WithArg<2>(
|
| + Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
|
| + base::Unretained(this), conn_id))));
|
| ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
|
| }
|
| }
|
| @@ -1221,8 +1236,8 @@ TEST_P(BufferedPacketStoreTest, DeliverEmptyPackets) {
|
| ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
|
| }
|
|
|
| -// Tests that by the time a retransmitted CHLO arrives, a connection for the
|
| -// CHLO should already be created.
|
| +// Tests that a retransmitted CHLO arrives after a connection for the
|
| +// CHLO has been created.
|
| TEST_P(BufferedPacketStoreTest, ReceiveRetransmittedCHLO) {
|
| InSequence s;
|
| IPEndPoint client_address(Loopback4(), 1);
|
| @@ -1281,6 +1296,203 @@ TEST_P(BufferedPacketStoreTest, ReceiveCHLOAfterExpiration) {
|
| ProcessPacket(client_address, conn_id, true, false, SerializeFullCHLO());
|
| }
|
|
|
| +TEST_P(BufferedPacketStoreTest, ProcessCHLOsUptoLimitAndBufferTheRest) {
|
| + FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
|
| + // Process more than (|kMaxNumSessionsToCreate| +
|
| + // |kDefaultMaxConnectionsInStore|) CHLOs,
|
| + // the first |kMaxNumSessionsToCreate| should create connections immediately,
|
| + // the next |kDefaultMaxConnectionsInStore| should be buffered,
|
| + // the rest should be dropped.
|
| + QuicBufferedPacketStore* store =
|
| + QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
|
| + const size_t kNumCHLOs =
|
| + kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore + 1;
|
| + for (size_t conn_id = 1; conn_id <= kNumCHLOs; ++conn_id) {
|
| + if (conn_id < kNumCHLOs) {
|
| + // Except the last connection, all connections for previous CHLOs should
|
| + // be regarded as newly added.
|
| + EXPECT_CALL(*dispatcher_, OnNewConnectionAdded(conn_id));
|
| + }
|
| + if (conn_id <= kMaxNumSessionsToCreate) {
|
| + EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
|
| + .WillOnce(testing::Return(CreateSession(
|
| + dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
|
| + &mock_alarm_factory_, &crypto_config_,
|
| + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
|
| + EXPECT_CALL(
|
| + *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
|
| + ProcessUdpPacket(_, _, _))
|
| + .WillOnce(testing::WithArg<2>(
|
| + Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
|
| + base::Unretained(this), conn_id))));
|
| + }
|
| + ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
|
| + if (conn_id <= kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore &&
|
| + conn_id > kMaxNumSessionsToCreate) {
|
| + EXPECT_TRUE(store->HasChloForConnection(conn_id));
|
| + } else {
|
| + // First |kMaxNumSessionsToCreate| CHLOs should be passed to new
|
| + // connections immediately, and the last CHLO should be dropped as the
|
| + // store is full.
|
| + EXPECT_FALSE(store->HasChloForConnection(conn_id));
|
| + }
|
| + }
|
| +
|
| + // Graduately consume buffered CHLOs. The buffered connections should be
|
| + // created but the dropped one shouldn't.
|
| + for (size_t conn_id = kMaxNumSessionsToCreate + 1;
|
| + conn_id <= kMaxNumSessionsToCreate + kDefaultMaxConnectionsInStore;
|
| + ++conn_id) {
|
| + EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
|
| + .WillOnce(testing::Return(CreateSession(
|
| + dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
|
| + &mock_alarm_factory_, &crypto_config_,
|
| + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
|
| + EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
|
| + ProcessUdpPacket(_, _, _))
|
| + .WillOnce(testing::WithArg<2>(
|
| + Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
|
| + base::Unretained(this), conn_id))));
|
| + }
|
| + EXPECT_CALL(*dispatcher_, CreateQuicSession(kNumCHLOs, client_addr_))
|
| + .Times(0);
|
| +
|
| + while (store->HasChlosBuffered()) {
|
| + dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
|
| + }
|
| +
|
| + EXPECT_EQ(static_cast<size_t>(kMaxNumSessionsToCreate) +
|
| + kDefaultMaxConnectionsInStore,
|
| + session1_->connection_id());
|
| +}
|
| +
|
| +// Duplicated CHLO shouldn't be buffered.
|
| +TEST_P(BufferedPacketStoreTest, DropDuplicatedCHLO) {
|
| + FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
|
| + for (QuicConnectionId conn_id = 1; conn_id <= kMaxNumSessionsToCreate + 1;
|
| + ++conn_id) {
|
| + // Last CHLO will be buffered. Others will create connection right away.
|
| + if (conn_id <= kMaxNumSessionsToCreate) {
|
| + EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
|
| + .WillOnce(testing::Return(CreateSession(
|
| + dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
|
| + &mock_alarm_factory_, &crypto_config_,
|
| + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
|
| + EXPECT_CALL(
|
| + *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
|
| + ProcessUdpPacket(_, _, _))
|
| + .WillOnce(testing::WithArg<2>(
|
| + Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
|
| + base::Unretained(this), conn_id))));
|
| + }
|
| + ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
|
| + }
|
| + // Retransmit CHLO on last connection should be dropped.
|
| + QuicConnectionId last_connection = kMaxNumSessionsToCreate + 1;
|
| + ProcessPacket(client_addr_, last_connection, true, false,
|
| + SerializeFullCHLO());
|
| +
|
| + // Reset counter and process buffered CHLO.
|
| + EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection, client_addr_))
|
| + .WillOnce(testing::Return(CreateSession(
|
| + dispatcher_.get(), config_, last_connection, client_addr_,
|
| + &mock_helper_, &mock_alarm_factory_, &crypto_config_,
|
| + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
|
| + // Only one packet(CHLO) should be process.
|
| + EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
|
| + ProcessUdpPacket(_, _, _))
|
| + .WillOnce(testing::WithArg<2>(
|
| + Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
|
| + base::Unretained(this), last_connection))));
|
| + dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
|
| +}
|
| +
|
| +TEST_P(BufferedPacketStoreTest, BufferNonChloPacketsUptoLimitWithChloBuffered) {
|
| + FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
|
| + QuicConnectionId last_connection_id = kMaxNumSessionsToCreate + 1;
|
| + for (QuicConnectionId conn_id = 1; conn_id <= last_connection_id; ++conn_id) {
|
| + // Last CHLO will be buffered. Others will create connection right away.
|
| + if (conn_id <= kMaxNumSessionsToCreate) {
|
| + EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
|
| + .WillOnce(testing::Return(CreateSession(
|
| + dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
|
| + &mock_alarm_factory_, &crypto_config_,
|
| + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
|
| + EXPECT_CALL(
|
| + *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
|
| + ProcessUdpPacket(_, _, _))
|
| + .WillOnce(testing::WithArg<2>(
|
| + Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
|
| + base::Unretained(this), conn_id))));
|
| + }
|
| + ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
|
| + }
|
| +
|
| + // Process another |kDefaultMaxUndecryptablePackets| + 1 data packets. The
|
| + // last one should be dropped.
|
| + for (QuicPacketNumber packet_number = 2;
|
| + packet_number <= kDefaultMaxUndecryptablePackets + 2; ++packet_number) {
|
| + ProcessPacket(client_addr_, last_connection_id, true, false, "data packet");
|
| + }
|
| +
|
| + // Reset counter and process buffered CHLO.
|
| + EXPECT_CALL(*dispatcher_, CreateQuicSession(last_connection_id, client_addr_))
|
| + .WillOnce(testing::Return(CreateSession(
|
| + dispatcher_.get(), config_, last_connection_id, client_addr_,
|
| + &mock_helper_, &mock_alarm_factory_, &crypto_config_,
|
| + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
|
| + // Only CHLO and following |kDefaultMaxUndecryptablePackets| data packets
|
| + // should be process.
|
| + EXPECT_CALL(*reinterpret_cast<MockQuicConnection*>(session1_->connection()),
|
| + ProcessUdpPacket(_, _, _))
|
| + .Times(kDefaultMaxUndecryptablePackets + 1)
|
| + .WillRepeatedly(testing::WithArg<2>(
|
| + Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
|
| + base::Unretained(this), last_connection_id))));
|
| + dispatcher_->ProcessBufferedChlos(kMaxNumSessionsToCreate);
|
| +}
|
| +
|
| +// Tests that when dispatcher's packet buffer is full, a CHLO on connection
|
| +// which doesn't have buffered CHLO should be buffered.
|
| +TEST_P(BufferedPacketStoreTest, ReceiveCHLOForBufferedConnection) {
|
| + FLAGS_quic_limit_num_new_sessions_per_epoll_loop = true;
|
| + QuicBufferedPacketStore* store =
|
| + QuicDispatcherPeer::GetBufferedPackets(dispatcher_.get());
|
| +
|
| + QuicConnectionId conn_id = 1;
|
| + ProcessPacket(client_addr_, conn_id, true, false, "data packet",
|
| + PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER,
|
| + kDefaultPathId,
|
| + /*packet_number=*/1);
|
| + // Fill packet buffer to full with CHLOs on other connections. Need to feed
|
| + // extra CHLOs because the first |kMaxNumSessionsToCreate| are going to create
|
| + // session directly.
|
| + for (conn_id = 2;
|
| + conn_id <= kDefaultMaxConnectionsInStore + kMaxNumSessionsToCreate;
|
| + ++conn_id) {
|
| + if (conn_id <= kMaxNumSessionsToCreate + 1) {
|
| + EXPECT_CALL(*dispatcher_, CreateQuicSession(conn_id, client_addr_))
|
| + .WillOnce(testing::Return(CreateSession(
|
| + dispatcher_.get(), config_, conn_id, client_addr_, &mock_helper_,
|
| + &mock_alarm_factory_, &crypto_config_,
|
| + QuicDispatcherPeer::GetCache(dispatcher_.get()), &session1_)));
|
| + EXPECT_CALL(
|
| + *reinterpret_cast<MockQuicConnection*>(session1_->connection()),
|
| + ProcessUdpPacket(_, _, _))
|
| + .WillOnce(testing::WithArg<2>(
|
| + Invoke(CreateFunctor(&QuicDispatcherTest::ValidatePacket,
|
| + base::Unretained(this), conn_id))));
|
| + }
|
| + ProcessPacket(client_addr_, conn_id, true, false, SerializeFullCHLO());
|
| + }
|
| + EXPECT_FALSE(store->HasChloForConnection(/*connection_id=*/1));
|
| +
|
| + // CHLO on connection 1 should still be buffered.
|
| + ProcessPacket(client_addr_, /*connection_id=*/1, true, false,
|
| + SerializeFullCHLO());
|
| + EXPECT_TRUE(store->HasChloForConnection(/*connection_id=*/1));
|
| +}
|
| +
|
| } // namespace
|
| } // namespace test
|
| } // namespace net
|
|
|