| // Copyright 2013 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. |
| |
| #include "quic/tools/quic_server.h" |
| |
| #include "absl/base/macros.h" |
| #include "quic/core/crypto/quic_random.h" |
| #include "quic/core/quic_epoll_alarm_factory.h" |
| #include "quic/core/quic_epoll_connection_helper.h" |
| #include "quic/core/quic_utils.h" |
| #include "quic/platform/api/quic_flags.h" |
| #include "quic/platform/api/quic_logging.h" |
| #include "quic/platform/api/quic_port_utils.h" |
| #include "quic/platform/api/quic_socket_address.h" |
| #include "quic/platform/api/quic_test.h" |
| #include "quic/platform/api/quic_test_loopback.h" |
| #include "quic/test_tools/crypto_test_utils.h" |
| #include "quic/test_tools/mock_quic_dispatcher.h" |
| #include "quic/test_tools/quic_server_peer.h" |
| #include "quic/tools/quic_memory_cache_backend.h" |
| #include "quic/tools/quic_simple_crypto_server_stream_helper.h" |
| |
| namespace quic { |
| namespace test { |
| |
| using ::testing::_; |
| |
| namespace { |
| |
| class MockQuicSimpleDispatcher : public QuicSimpleDispatcher { |
| public: |
| MockQuicSimpleDispatcher( |
| const QuicConfig* config, |
| const QuicCryptoServerConfig* crypto_config, |
| QuicVersionManager* version_manager, |
| std::unique_ptr<QuicConnectionHelperInterface> helper, |
| std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper, |
| std::unique_ptr<QuicAlarmFactory> alarm_factory, |
| QuicSimpleServerBackend* quic_simple_server_backend) |
| : QuicSimpleDispatcher(config, |
| crypto_config, |
| version_manager, |
| std::move(helper), |
| std::move(session_helper), |
| std::move(alarm_factory), |
| quic_simple_server_backend, |
| kQuicDefaultConnectionIdLength) {} |
| ~MockQuicSimpleDispatcher() override = default; |
| |
| MOCK_METHOD(void, OnCanWrite, (), (override)); |
| MOCK_METHOD(bool, HasPendingWrites, (), (const, override)); |
| MOCK_METHOD(bool, HasChlosBuffered, (), (const, override)); |
| MOCK_METHOD(void, ProcessBufferedChlos, (size_t), (override)); |
| }; |
| |
| class TestQuicServer : public QuicServer { |
| public: |
| TestQuicServer() |
| : QuicServer(crypto_test_utils::ProofSourceForTesting(), |
| &quic_simple_server_backend_) {} |
| |
| ~TestQuicServer() override = default; |
| |
| MockQuicSimpleDispatcher* mock_dispatcher() { return mock_dispatcher_; } |
| |
| protected: |
| QuicDispatcher* CreateQuicDispatcher() override { |
| mock_dispatcher_ = new MockQuicSimpleDispatcher( |
| &config(), &crypto_config(), version_manager(), |
| std::unique_ptr<QuicEpollConnectionHelper>( |
| new QuicEpollConnectionHelper(epoll_server(), |
| QuicAllocator::BUFFER_POOL)), |
| std::unique_ptr<QuicCryptoServerStreamBase::Helper>( |
| new QuicSimpleCryptoServerStreamHelper()), |
| std::unique_ptr<QuicEpollAlarmFactory>( |
| new QuicEpollAlarmFactory(epoll_server())), |
| &quic_simple_server_backend_); |
| return mock_dispatcher_; |
| } |
| |
| MockQuicSimpleDispatcher* mock_dispatcher_ = nullptr; |
| QuicMemoryCacheBackend quic_simple_server_backend_; |
| }; |
| |
| class QuicServerEpollInTest : public QuicTest { |
| public: |
| QuicServerEpollInTest() |
| : port_(QuicPickServerPortForTestsOrDie()), |
| server_address_(TestLoopback(), port_) {} |
| |
| void StartListening() { |
| server_.CreateUDPSocketAndListen(server_address_); |
| server_address_ = QuicSocketAddress(server_address_.host(), server_.port()); |
| |
| ASSERT_TRUE(QuicServerPeer::SetSmallSocket(&server_)); |
| |
| if (!server_.overflow_supported()) { |
| QUIC_LOG(WARNING) << "Overflow not supported. Not testing."; |
| return; |
| } |
| } |
| |
| protected: |
| int port_; |
| QuicSocketAddress server_address_; |
| TestQuicServer server_; |
| }; |
| |
| // Tests that if dispatcher has CHLOs waiting for connection creation, EPOLLIN |
| // event should try to create connections for them. And set epoll mask with |
| // EPOLLIN if there are still CHLOs remaining at the end of epoll event. |
| TEST_F(QuicServerEpollInTest, ProcessBufferedCHLOsOnEpollin) { |
| // Given an EPOLLIN event, try to create session for buffered CHLOs. In first |
| // event, dispatcher can't create session for all of CHLOs. So listener should |
| // register another EPOLLIN event by itself. Even without new packet arrival, |
| // the rest CHLOs should be process in next epoll event. |
| StartListening(); |
| bool more_chlos = true; |
| MockQuicSimpleDispatcher* dispatcher_ = server_.mock_dispatcher(); |
| QUICHE_DCHECK(dispatcher_ != nullptr); |
| EXPECT_CALL(*dispatcher_, OnCanWrite()).Times(testing::AnyNumber()); |
| EXPECT_CALL(*dispatcher_, ProcessBufferedChlos(_)).Times(2); |
| EXPECT_CALL(*dispatcher_, HasPendingWrites()).Times(testing::AnyNumber()); |
| // Expect there are still CHLOs buffered after 1st event. But not any more |
| // after 2nd event. |
| EXPECT_CALL(*dispatcher_, HasChlosBuffered()) |
| .WillOnce(testing::Return(true)) |
| .WillOnce( |
| DoAll(testing::Assign(&more_chlos, false), testing::Return(false))); |
| |
| // Send a packet to trigger epoll event. |
| int fd = socket( |
| AddressFamilyUnderTest() == IpAddressFamily::IP_V4 ? AF_INET : AF_INET6, |
| SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP); |
| ASSERT_LT(0, fd); |
| |
| char buf[1024]; |
| memset(buf, 0, ABSL_ARRAYSIZE(buf)); |
| sockaddr_storage storage = server_address_.generic_address(); |
| int rc = sendto(fd, buf, ABSL_ARRAYSIZE(buf), 0, |
| reinterpret_cast<sockaddr*>(&storage), sizeof(storage)); |
| if (rc < 0) { |
| QUIC_DLOG(INFO) << errno << " " << strerror(errno); |
| } |
| |
| while (more_chlos) { |
| server_.WaitForEvents(); |
| } |
| } |
| |
| class QuicServerDispatchPacketTest : public QuicTest { |
| public: |
| QuicServerDispatchPacketTest() |
| : crypto_config_("blah", |
| QuicRandom::GetInstance(), |
| crypto_test_utils::ProofSourceForTesting(), |
| KeyExchangeSource::Default()), |
| version_manager_(AllSupportedVersions()), |
| dispatcher_( |
| &config_, |
| &crypto_config_, |
| &version_manager_, |
| std::unique_ptr<QuicEpollConnectionHelper>( |
| new QuicEpollConnectionHelper(&eps_, |
| QuicAllocator::BUFFER_POOL)), |
| std::unique_ptr<QuicCryptoServerStreamBase::Helper>( |
| new QuicSimpleCryptoServerStreamHelper()), |
| std::unique_ptr<QuicEpollAlarmFactory>( |
| new QuicEpollAlarmFactory(&eps_)), |
| &quic_simple_server_backend_) { |
| dispatcher_.InitializeWithWriter(new QuicDefaultPacketWriter(1234)); |
| } |
| |
| void DispatchPacket(const QuicReceivedPacket& packet) { |
| QuicSocketAddress client_addr, server_addr; |
| dispatcher_.ProcessPacket(server_addr, client_addr, packet); |
| } |
| |
| protected: |
| QuicConfig config_; |
| QuicCryptoServerConfig crypto_config_; |
| QuicVersionManager version_manager_; |
| QuicEpollServer eps_; |
| QuicMemoryCacheBackend quic_simple_server_backend_; |
| MockQuicDispatcher dispatcher_; |
| }; |
| |
| TEST_F(QuicServerDispatchPacketTest, DispatchPacket) { |
| // clang-format off |
| unsigned char valid_packet[] = { |
| // public flags (8 byte connection_id) |
| 0x3C, |
| // connection_id |
| 0x10, 0x32, 0x54, 0x76, |
| 0x98, 0xBA, 0xDC, 0xFE, |
| // packet number |
| 0xBC, 0x9A, 0x78, 0x56, |
| 0x34, 0x12, |
| // private flags |
| 0x00 |
| }; |
| // clang-format on |
| QuicReceivedPacket encrypted_valid_packet( |
| reinterpret_cast<char*>(valid_packet), ABSL_ARRAYSIZE(valid_packet), |
| QuicTime::Zero(), false); |
| |
| EXPECT_CALL(dispatcher_, ProcessPacket(_, _, _)).Times(1); |
| DispatchPacket(encrypted_valid_packet); |
| } |
| |
| } // namespace |
| } // namespace test |
| } // namespace quic |