|  | // Copyright (c) 2019 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. | 
|  |  | 
|  | // Sets up a dispatcher and sends requests via the QboneClient. | 
|  |  | 
|  | #include "net/third_party/quiche/src/quic/qbone/qbone_client.h" | 
|  |  | 
|  | #include "net/third_party/quiche/src/quic/core/quic_alarm_factory.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_default_packet_writer.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_dispatcher.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_epoll_alarm_factory.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_epoll_connection_helper.h" | 
|  | #include "net/third_party/quiche/src/quic/core/quic_packet_reader.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_mutex.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_port_utils.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_socket_address.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" | 
|  | #include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h" | 
|  | #include "net/quic/platform/impl/quic_socket_utils.h" | 
|  | #include "net/third_party/quiche/src/quic/qbone/qbone_constants.h" | 
|  | #include "net/third_party/quiche/src/quic/qbone/qbone_packet_processor_test_tools.h" | 
|  | #include "net/third_party/quiche/src/quic/qbone/qbone_server_session.h" | 
|  | #include "net/third_party/quiche/src/quic/test_tools/crypto_test_utils.h" | 
|  | #include "net/third_party/quiche/src/quic/test_tools/quic_server_peer.h" | 
|  | #include "net/third_party/quiche/src/quic/test_tools/server_thread.h" | 
|  | #include "net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h" | 
|  | #include "net/third_party/quiche/src/quic/tools/quic_server.h" | 
|  |  | 
|  | namespace quic { | 
|  | namespace test { | 
|  | namespace { | 
|  |  | 
|  | string TestPacketIn(const string& body) { | 
|  | return PrependIPv6HeaderForTest(body, 5); | 
|  | } | 
|  |  | 
|  | string TestPacketOut(const string& body) { | 
|  | return PrependIPv6HeaderForTest(body, 4); | 
|  | } | 
|  |  | 
|  | class DataSavingQbonePacketWriter : public QbonePacketWriter { | 
|  | public: | 
|  | void WritePacketToNetwork(const char* packet, size_t size) override { | 
|  | QuicWriterMutexLock lock(&mu_); | 
|  | data_.push_back(string(packet, size)); | 
|  | } | 
|  |  | 
|  | std::vector<string> data() { | 
|  | QuicWriterMutexLock lock(&mu_); | 
|  | return data_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | QuicMutex mu_; | 
|  | std::vector<string> data_; | 
|  | }; | 
|  |  | 
|  | // A subclass of a qbone session that will own the connection passed in. | 
|  | class ConnectionOwningQboneServerSession : public QboneServerSession { | 
|  | public: | 
|  | ConnectionOwningQboneServerSession( | 
|  | const ParsedQuicVersionVector& supported_versions, | 
|  | QuicConnection* connection, | 
|  | Visitor* owner, | 
|  | const QuicConfig& config, | 
|  | const QuicCryptoServerConfig* quic_crypto_server_config, | 
|  | QuicCompressedCertsCache* compressed_certs_cache, | 
|  | QbonePacketWriter* writer) | 
|  | : QboneServerSession(supported_versions, | 
|  | connection, | 
|  | owner, | 
|  | config, | 
|  | quic_crypto_server_config, | 
|  | compressed_certs_cache, | 
|  | writer, | 
|  | TestLoopback6(), | 
|  | TestLoopback6(), | 
|  | 64, | 
|  | nullptr), | 
|  | connection_(connection) {} | 
|  |  | 
|  | private: | 
|  | // Note that we don't expect the QboneServerSession or any of its parent | 
|  | // classes to do anything with the connection_ in their destructors. | 
|  | std::unique_ptr<QuicConnection> connection_; | 
|  | }; | 
|  |  | 
|  | class QuicQboneDispatcher : public QuicDispatcher { | 
|  | public: | 
|  | QuicQboneDispatcher( | 
|  | const QuicConfig* config, | 
|  | const QuicCryptoServerConfig* crypto_config, | 
|  | QuicVersionManager* version_manager, | 
|  | std::unique_ptr<QuicConnectionHelperInterface> helper, | 
|  | std::unique_ptr<QuicCryptoServerStream::Helper> session_helper, | 
|  | std::unique_ptr<QuicAlarmFactory> alarm_factory, | 
|  | QbonePacketWriter* writer) | 
|  | : QuicDispatcher(config, | 
|  | crypto_config, | 
|  | version_manager, | 
|  | std::move(helper), | 
|  | std::move(session_helper), | 
|  | std::move(alarm_factory), | 
|  | kQuicDefaultConnectionIdLength), | 
|  | writer_(writer) {} | 
|  |  | 
|  | QuicSession* CreateQuicSession( | 
|  | QuicConnectionId id, | 
|  | const QuicSocketAddress& client, | 
|  | QuicStringPiece alpn, | 
|  | const quic::ParsedQuicVersion& version) override { | 
|  | CHECK_EQ(alpn, "qbone"); | 
|  | QuicConnection* connection = | 
|  | new QuicConnection(id, client, helper(), alarm_factory(), writer(), | 
|  | /* owns_writer= */ false, Perspective::IS_SERVER, | 
|  | ParsedQuicVersionVector{version}); | 
|  | // The connection owning wrapper owns the connection created. | 
|  | QboneServerSession* session = new ConnectionOwningQboneServerSession( | 
|  | GetSupportedVersions(), connection, this, config(), crypto_config(), | 
|  | compressed_certs_cache(), writer_); | 
|  | session->Initialize(); | 
|  | return session; | 
|  | } | 
|  |  | 
|  | QuicConnectionId GenerateNewServerConnectionId( | 
|  | ParsedQuicVersion version, | 
|  | QuicConnectionId connection_id) const override { | 
|  | char connection_id_bytes[kQuicDefaultConnectionIdLength] = {}; | 
|  | return QuicConnectionId(connection_id_bytes, sizeof(connection_id_bytes)); | 
|  | } | 
|  |  | 
|  | private: | 
|  | QbonePacketWriter* writer_; | 
|  | }; | 
|  |  | 
|  | class QboneTestServer : public QuicServer { | 
|  | public: | 
|  | explicit QboneTestServer(std::unique_ptr<ProofSource> proof_source) | 
|  | : QuicServer(std::move(proof_source), &response_cache_) {} | 
|  | QuicDispatcher* CreateQuicDispatcher() override { | 
|  | QuicEpollAlarmFactory alarm_factory(epoll_server()); | 
|  | return new QuicQboneDispatcher( | 
|  | &config(), &crypto_config(), version_manager(), | 
|  | std::unique_ptr<QuicEpollConnectionHelper>( | 
|  | new QuicEpollConnectionHelper(epoll_server(), | 
|  | QuicAllocator::BUFFER_POOL)), | 
|  | std::unique_ptr<QuicCryptoServerStream::Helper>( | 
|  | new QboneCryptoServerStreamHelper()), | 
|  | std::unique_ptr<QuicEpollAlarmFactory>( | 
|  | new QuicEpollAlarmFactory(epoll_server())), | 
|  | &writer_); | 
|  | } | 
|  |  | 
|  | std::vector<string> data() { return writer_.data(); } | 
|  |  | 
|  | void WaitForDataSize(int n) { | 
|  | while (data().size() != n) { | 
|  | } | 
|  | } | 
|  |  | 
|  | private: | 
|  | quic::QuicMemoryCacheBackend response_cache_; | 
|  | DataSavingQbonePacketWriter writer_; | 
|  | }; | 
|  |  | 
|  | class QboneTestClient : public QboneClient { | 
|  | public: | 
|  | QboneTestClient(QuicSocketAddress server_address, | 
|  | const QuicServerId& server_id, | 
|  | const ParsedQuicVersionVector& supported_versions, | 
|  | QuicEpollServer* epoll_server, | 
|  | std::unique_ptr<ProofVerifier> proof_verifier) | 
|  | : QboneClient(server_address, | 
|  | server_id, | 
|  | supported_versions, | 
|  | /*session_owner=*/nullptr, | 
|  | QuicConfig(), | 
|  | epoll_server, | 
|  | std::move(proof_verifier), | 
|  | &qbone_writer_, | 
|  | nullptr) {} | 
|  |  | 
|  | ~QboneTestClient() override {} | 
|  |  | 
|  | void SendData(const string& data) { | 
|  | qbone_session()->ProcessPacketFromNetwork(data); | 
|  | } | 
|  |  | 
|  | void WaitForWriteToFlush() { | 
|  | while (connected() && session()->HasDataToWrite()) { | 
|  | WaitForEvents(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void WaitForDataSize(int n) { | 
|  | while (data().size() != n) { | 
|  | WaitForEvents(); | 
|  | } | 
|  | } | 
|  |  | 
|  | std::vector<string> data() { return qbone_writer_.data(); } | 
|  |  | 
|  | private: | 
|  | DataSavingQbonePacketWriter qbone_writer_; | 
|  | }; | 
|  |  | 
|  | TEST(QboneClientTest, SendDataFromClient) { | 
|  | auto server = new QboneTestServer(crypto_test_utils::ProofSourceForTesting()); | 
|  | QuicSocketAddress server_address(TestLoopback(), | 
|  | QuicPickServerPortForTestsOrDie()); | 
|  | ServerThread server_thread(server, server_address); | 
|  | server_thread.Initialize(); | 
|  | server_thread.Start(); | 
|  |  | 
|  | QuicEpollServer epoll_server; | 
|  | QboneTestClient client( | 
|  | server_address, | 
|  | QuicServerId("test.example.com", server_address.port(), false), | 
|  | AllSupportedVersions(), &epoll_server, | 
|  | crypto_test_utils::ProofVerifierForTesting()); | 
|  | ASSERT_TRUE(client.Initialize()); | 
|  | ASSERT_TRUE(client.Connect()); | 
|  | ASSERT_TRUE(client.WaitForCryptoHandshakeConfirmed()); | 
|  | client.SendData(TestPacketIn("hello")); | 
|  | client.SendData(TestPacketIn("world")); | 
|  | client.WaitForWriteToFlush(); | 
|  | server->WaitForDataSize(2); | 
|  | EXPECT_THAT(server->data()[0], testing::Eq(TestPacketOut("hello"))); | 
|  | EXPECT_THAT(server->data()[1], testing::Eq(TestPacketOut("world"))); | 
|  | auto server_session = | 
|  | static_cast<QboneServerSession*>(QuicServerPeer::GetDispatcher(server) | 
|  | ->session_map() | 
|  | .begin() | 
|  | ->second.get()); | 
|  | string long_data(QboneConstants::kMaxQbonePacketBytes - sizeof(ip6_hdr) - 1, | 
|  | 'A'); | 
|  | // Pretend the server gets data. | 
|  | server_thread.Schedule([&server_session, &long_data]() { | 
|  | server_session->ProcessPacketFromNetwork( | 
|  | TestPacketIn("Somethingsomething")); | 
|  | server_session->ProcessPacketFromNetwork(TestPacketIn(long_data)); | 
|  | server_session->ProcessPacketFromNetwork(TestPacketIn(long_data)); | 
|  | }); | 
|  | client.WaitForDataSize(3); | 
|  | EXPECT_THAT(client.data()[0], | 
|  | testing::Eq(TestPacketOut("Somethingsomething"))); | 
|  | EXPECT_THAT(client.data()[1], testing::Eq(TestPacketOut(long_data))); | 
|  | EXPECT_THAT(client.data()[2], testing::Eq(TestPacketOut(long_data))); | 
|  |  | 
|  | client.Disconnect(); | 
|  | server_thread.Quit(); | 
|  | server_thread.Join(); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace test | 
|  | }  // namespace quic |