xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/qbone/qbone_client_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Sets up a dispatcher and sends requests via the QboneClient.
6 
7 #include "quiche/quic/qbone/qbone_client.h"
8 
9 #include <memory>
10 
11 #include "absl/strings/string_view.h"
12 #include "quiche/quic/core/io/quic_default_event_loop.h"
13 #include "quiche/quic/core/io/quic_event_loop.h"
14 #include "quiche/quic/core/quic_alarm_factory.h"
15 #include "quiche/quic/core/quic_default_clock.h"
16 #include "quiche/quic/core/quic_default_connection_helper.h"
17 #include "quiche/quic/core/quic_dispatcher.h"
18 #include "quiche/quic/core/quic_types.h"
19 #include "quiche/quic/core/quic_versions.h"
20 #include "quiche/quic/platform/api/quic_flags.h"
21 #include "quiche/quic/platform/api/quic_mutex.h"
22 #include "quiche/quic/platform/api/quic_socket_address.h"
23 #include "quiche/quic/platform/api/quic_test.h"
24 #include "quiche/quic/platform/api/quic_test_loopback.h"
25 #include "quiche/quic/qbone/qbone_packet_processor_test_tools.h"
26 #include "quiche/quic/qbone/qbone_server_session.h"
27 #include "quiche/quic/test_tools/crypto_test_utils.h"
28 #include "quiche/quic/test_tools/quic_connection_peer.h"
29 #include "quiche/quic/test_tools/quic_dispatcher_peer.h"
30 #include "quiche/quic/test_tools/quic_server_peer.h"
31 #include "quiche/quic/test_tools/server_thread.h"
32 #include "quiche/quic/tools/quic_memory_cache_backend.h"
33 #include "quiche/quic/tools/quic_server.h"
34 
35 namespace quic {
36 namespace test {
37 namespace {
38 
39 using ::testing::ElementsAre;
40 
GetTestParams()41 ParsedQuicVersionVector GetTestParams() {
42   ParsedQuicVersionVector test_versions;
43   SetQuicReloadableFlag(quic_disable_version_q046, false);
44   return CurrentSupportedVersionsWithQuicCrypto();
45 }
46 
TestPacketIn(const std::string & body)47 std::string TestPacketIn(const std::string& body) {
48   return PrependIPv6HeaderForTest(body, 5);
49 }
50 
TestPacketOut(const std::string & body)51 std::string TestPacketOut(const std::string& body) {
52   return PrependIPv6HeaderForTest(body, 4);
53 }
54 
55 class DataSavingQbonePacketWriter : public QbonePacketWriter {
56  public:
WritePacketToNetwork(const char * packet,size_t size)57   void WritePacketToNetwork(const char* packet, size_t size) override {
58     QuicWriterMutexLock lock(&mu_);
59     data_.push_back(std::string(packet, size));
60   }
61 
data()62   std::vector<std::string> data() {
63     QuicWriterMutexLock lock(&mu_);
64     return data_;
65   }
66 
67  private:
68   QuicMutex mu_;
69   std::vector<std::string> data_;
70 };
71 
72 // A subclass of a QBONE session that will own the connection passed in.
73 class ConnectionOwningQboneServerSession : public QboneServerSession {
74  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)75   ConnectionOwningQboneServerSession(
76       const ParsedQuicVersionVector& supported_versions,
77       QuicConnection* connection, Visitor* owner, const QuicConfig& config,
78       const QuicCryptoServerConfig* quic_crypto_server_config,
79       QuicCompressedCertsCache* compressed_certs_cache,
80       QbonePacketWriter* writer)
81       : QboneServerSession(supported_versions, connection, owner, config,
82                            quic_crypto_server_config, compressed_certs_cache,
83                            writer, TestLoopback6(), TestLoopback6(), 64,
84                            nullptr),
85         connection_(connection) {}
86 
87  private:
88   // Note that we don't expect the QboneServerSession or any of its parent
89   // classes to do anything with the connection_ in their destructors.
90   std::unique_ptr<QuicConnection> connection_;
91 };
92 
93 class QuicQboneDispatcher : public QuicDispatcher {
94  public:
QuicQboneDispatcher(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,QbonePacketWriter * writer,ConnectionIdGeneratorInterface & generator)95   QuicQboneDispatcher(
96       const QuicConfig* config, const QuicCryptoServerConfig* crypto_config,
97       QuicVersionManager* version_manager,
98       std::unique_ptr<QuicConnectionHelperInterface> helper,
99       std::unique_ptr<QuicCryptoServerStreamBase::Helper> session_helper,
100       std::unique_ptr<QuicAlarmFactory> alarm_factory,
101       QbonePacketWriter* writer, ConnectionIdGeneratorInterface& generator)
102       : QuicDispatcher(config, crypto_config, version_manager,
103                        std::move(helper), std::move(session_helper),
104                        std::move(alarm_factory), kQuicDefaultConnectionIdLength,
105                        generator),
106         writer_(writer) {}
107 
CreateQuicSession(QuicConnectionId id,const QuicSocketAddress & self_address,const QuicSocketAddress & peer_address,absl::string_view alpn,const ParsedQuicVersion & version,const ParsedClientHello &,ConnectionIdGeneratorInterface & connection_id_generator)108   std::unique_ptr<QuicSession> CreateQuicSession(
109       QuicConnectionId id, const QuicSocketAddress& self_address,
110       const QuicSocketAddress& peer_address, absl::string_view alpn,
111       const ParsedQuicVersion& version,
112       const ParsedClientHello& /*parsed_chlo*/,
113       ConnectionIdGeneratorInterface& connection_id_generator) override {
114     QUICHE_CHECK_EQ(alpn, "qbone");
115     QuicConnection* connection = new QuicConnection(
116         id, self_address, peer_address, helper(), alarm_factory(), writer(),
117         /* owns_writer= */ false, Perspective::IS_SERVER,
118         ParsedQuicVersionVector{version}, connection_id_generator);
119     // The connection owning wrapper owns the connection created.
120     auto session = std::make_unique<ConnectionOwningQboneServerSession>(
121         GetSupportedVersions(), connection, this, config(), crypto_config(),
122         compressed_certs_cache(), writer_);
123     session->Initialize();
124     return session;
125   }
126 
127  private:
128   QbonePacketWriter* writer_;
129 };
130 
131 class QboneTestServer : public QuicServer {
132  public:
QboneTestServer(std::unique_ptr<ProofSource> proof_source,quic::QuicMemoryCacheBackend * response_cache)133   explicit QboneTestServer(std::unique_ptr<ProofSource> proof_source,
134                            quic::QuicMemoryCacheBackend* response_cache)
135       : QuicServer(std::move(proof_source), response_cache) {}
CreateQuicDispatcher()136   QuicDispatcher* CreateQuicDispatcher() override {
137     return new QuicQboneDispatcher(
138         &config(), &crypto_config(), version_manager(),
139         std::make_unique<QuicDefaultConnectionHelper>(),
140         std::make_unique<QboneCryptoServerStreamHelper>(),
141         event_loop()->CreateAlarmFactory(), &writer_,
142         connection_id_generator());
143   }
144 
data()145   std::vector<std::string> data() { return writer_.data(); }
146 
147  private:
148   DataSavingQbonePacketWriter writer_;
149 };
150 
151 class QboneTestClient : public QboneClient {
152  public:
QboneTestClient(QuicSocketAddress server_address,const QuicServerId & server_id,const ParsedQuicVersionVector & supported_versions,QuicEventLoop * event_loop,std::unique_ptr<ProofVerifier> proof_verifier)153   QboneTestClient(QuicSocketAddress server_address,
154                   const QuicServerId& server_id,
155                   const ParsedQuicVersionVector& supported_versions,
156                   QuicEventLoop* event_loop,
157                   std::unique_ptr<ProofVerifier> proof_verifier)
158       : QboneClient(server_address, server_id, supported_versions,
159                     /*session_owner=*/nullptr, QuicConfig(), event_loop,
160                     std::move(proof_verifier), &qbone_writer_, nullptr) {}
161 
~QboneTestClient()162   ~QboneTestClient() override {}
163 
SendData(const std::string & data)164   void SendData(const std::string& data) {
165     qbone_session()->ProcessPacketFromNetwork(data);
166   }
167 
WaitForWriteToFlush()168   void WaitForWriteToFlush() {
169     while (connected() && session()->HasDataToWrite()) {
170       WaitForEvents();
171     }
172   }
173 
174   // Returns true when the data size is reached or false on timeouts.
WaitForDataSize(int n,QuicTime::Delta timeout)175   bool WaitForDataSize(int n, QuicTime::Delta timeout) {
176     const QuicClock* clock =
177         quic::test::QuicConnectionPeer::GetHelper(session()->connection())
178             ->GetClock();
179     const QuicTime deadline = clock->Now() + timeout;
180     while (data().size() < n) {
181       if (clock->Now() > deadline) {
182         return false;
183       }
184       WaitForEvents();
185     }
186     return true;
187   }
188 
data()189   std::vector<std::string> data() { return qbone_writer_.data(); }
190 
191  private:
192   DataSavingQbonePacketWriter qbone_writer_;
193 };
194 
195 class QboneClientTest : public QuicTestWithParam<ParsedQuicVersion> {};
196 
197 INSTANTIATE_TEST_SUITE_P(Tests, QboneClientTest,
198                          ::testing::ValuesIn(GetTestParams()),
199                          ::testing::PrintToStringParamName());
200 
TEST_P(QboneClientTest,SendDataFromClient)201 TEST_P(QboneClientTest, SendDataFromClient) {
202   quic::QuicMemoryCacheBackend server_backend;
203   auto server = std::make_unique<QboneTestServer>(
204       crypto_test_utils::ProofSourceForTesting(), &server_backend);
205   QboneTestServer* server_ptr = server.get();
206   QuicSocketAddress server_address(TestLoopback(), 0);
207   ServerThread server_thread(std::move(server), server_address);
208   server_thread.Initialize();
209   server_address =
210       QuicSocketAddress(server_address.host(), server_thread.GetPort());
211   server_thread.Start();
212 
213   std::unique_ptr<QuicEventLoop> event_loop =
214       GetDefaultEventLoop()->Create(quic::QuicDefaultClock::Get());
215   QboneTestClient client(
216       server_address,
217       QuicServerId("test.example.com", server_address.port(), false),
218       ParsedQuicVersionVector{GetParam()}, event_loop.get(),
219       crypto_test_utils::ProofVerifierForTesting());
220   ASSERT_TRUE(client.Initialize());
221   ASSERT_TRUE(client.Connect());
222   ASSERT_TRUE(client.WaitForOneRttKeysAvailable());
223   client.SendData(TestPacketIn("hello"));
224   client.SendData(TestPacketIn("world"));
225   client.WaitForWriteToFlush();
226 
227   // Wait until the server has received at least two packets, timeout after 5s.
228   ASSERT_TRUE(
229       server_thread.WaitUntil([&] { return server_ptr->data().size() >= 2; },
230                               QuicTime::Delta::FromSeconds(5)));
231 
232   // Pretend the server gets data.
233   std::string long_data(1000, 'A');
234   server_thread.Schedule([server_ptr, &long_data]() {
235     EXPECT_THAT(server_ptr->data(),
236                 ElementsAre(TestPacketOut("hello"), TestPacketOut("world")));
237     auto server_session = static_cast<QboneServerSession*>(
238         QuicDispatcherPeer::GetFirstSessionIfAny(
239             QuicServerPeer::GetDispatcher(server_ptr)));
240     server_session->ProcessPacketFromNetwork(
241         TestPacketIn("Somethingsomething"));
242     server_session->ProcessPacketFromNetwork(TestPacketIn(long_data));
243     server_session->ProcessPacketFromNetwork(TestPacketIn(long_data));
244   });
245 
246   EXPECT_TRUE(client.WaitForDataSize(3, QuicTime::Delta::FromSeconds(5)));
247   EXPECT_THAT(client.data(),
248               ElementsAre(TestPacketOut("Somethingsomething"),
249                           TestPacketOut(long_data), TestPacketOut(long_data)));
250 
251   client.Disconnect();
252   server_thread.Quit();
253   server_thread.Join();
254 }
255 
256 }  // namespace
257 }  // namespace test
258 }  // namespace quic
259