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