Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(252)

Side by Side Diff: webrtc/p2p/quic/quicsession_unittest.cc

Issue 1648763002: Create QuicSession (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Fix broken unit tests Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <string>
12 #include <vector>
13
14 #include "webrtc/p2p/quic/quicconnectionhelper.h"
15 #include "webrtc/p2p/quic/quicsession.h"
16 #include "webrtc/p2p/quic/reliablequicstream.h"
17
18 #include "net/base/ip_endpoint.h"
19 #include "net/quic/crypto/crypto_server_config_protobuf.h"
20 #include "net/quic/crypto/quic_random.h"
21 #include "net/quic/crypto/proof_source.h"
22 #include "net/quic/crypto/proof_verifier.h"
23 #include "net/quic/crypto/quic_crypto_client_config.h"
24 #include "net/quic/crypto/quic_crypto_server_config.h"
25 #include "net/quic/quic_crypto_client_stream.h"
26 #include "net/quic/quic_crypto_server_stream.h"
27
28 #include "webrtc/base/common.h"
29 #include "webrtc/base/gunit.h"
30
31 #include "webrtc/p2p/base/faketransportcontroller.h"
32
33 using net::IPAddressNumber;
34 using net::IPEndPoint;
35 using net::Perspective;
36 using net::ProofVerifyContext;
37 using net::ProofVerifyDetails;
38 using net::QuicByteCount;
39 using net::QuicClock;
40 using net::QuicConfig;
41 using net::QuicConnection;
42 using net::QuicCryptoClientConfig;
43 using net::QuicCryptoServerConfig;
44 using net::QuicCryptoClientStream;
45 using net::QuicCryptoServerStream;
46 using net::QuicCryptoStream;
47 using net::QuicErrorCode;
48 using net::QuicPacketWriter;
49 using net::QuicRandom;
50 using net::QuicServerConfigProtobuf;
51 using net::QuicServerId;
52 using net::QuicStreamId;
53 using net::WriteResult;
54 using net::WriteStatus;
55
56 using cricket::FakeTransportChannel;
57 using cricket::QuicConnectionHelper;
58 using cricket::QuicSession;
59 using cricket::ReliableQuicStream;
60 using cricket::TransportChannel;
61
62 using rtc::Thread;
63
64 // Timeout for running asynchronous operations within unit tests
65 const int kTimeoutMs = 1000;
66 // Testing SpdyPriority value for creating outgoing ReliableQuicStream
67 const uint8 kDefaultPriority = 3;
68 // TExport keying material function
69 const char kExporterLabel[] = "label";
70 const char kExporterContext[] = "context";
71 const size_t kExporterContextLen = sizeof(kExporterContext);
72 // Identifies QUIC server session
73 const QuicServerId kServerId("www.google.com", 443);
74
75 // Used by QuicCryptoServerConfig to provide server credentials, returning a
76 // canned response equal to |success|
77 class FakeProofSource : public net::ProofSource {
78 public:
79 explicit FakeProofSource(bool success) : success_(success) {}
80 ~FakeProofSource() override {}
81
82 // ProofSource override
83 bool GetProof(const net::IPAddressNumber& server_ip,
84 const std::string& hostname,
85 const std::string& server_config,
86 bool ecdsa_ok,
87 const std::vector<std::string>** out_certs,
88 std::string* out_signature,
89 std::string* out_leaf_cert_sct) override {
90 if (success_) {
91 std::vector<std::string>* certs = new std::vector<std::string>();
92 certs->push_back("Required to establish handshake");
93 std::string signature("Signature");
94
95 *out_certs = certs;
96 *out_signature = signature;
97 }
98 return success_;
99 }
100
101 private:
102 // Whether or not obtaining proof source succeeds
103 bool success_;
104 };
105
106 // Used by QuicCryptoClientConfig to verify server credentials, returning a
107 // canned response of QUIC_SUCCESS if |success| is true
108 class FakeProofVerifier : public net::ProofVerifier {
109 public:
110 explicit FakeProofVerifier(bool success) : success_(success) {}
111 ~FakeProofVerifier() override {}
112
113 // ProofVerifier override
114 net::QuicAsyncStatus VerifyProof(
115 const std::string& hostname,
116 const std::string& server_config,
117 const std::vector<std::string>& certs,
118 const std::string& cert_sct,
119 const std::string& signature,
120 const net::ProofVerifyContext* verify_context,
121 std::string* error_details,
122 scoped_ptr<net::ProofVerifyDetails>* verify_details,
123 net::ProofVerifierCallback* callback) override {
124 return success_ ? net::QUIC_SUCCESS : net::QUIC_FAILURE;
125 }
126
127 private:
128 // Whether or not proof verification succeeds
129 bool success_;
130 };
131
132 // Writes QUIC packets to a fake transport channel that simulates a network
133 class FakeQuicPacketWriter : public QuicPacketWriter {
134 public:
135 explicit FakeQuicPacketWriter(FakeTransportChannel* fake_channel)
136 : fake_channel_(fake_channel) {}
137
138 virtual ~FakeQuicPacketWriter() {}
139
140 // Sends packets across the network
141 WriteResult WritePacket(const char* buffer,
142 size_t buf_len,
143 const IPAddressNumber& self_address,
144 const IPEndPoint& peer_address) override {
145 rtc::PacketOptions packet_options;
146 int rv = fake_channel_->SendPacket(buffer, buf_len, packet_options, 0);
147 net::WriteStatus status;
148 if (rv > 0) {
149 status = net::WRITE_STATUS_OK;
150 } else if (fake_channel_->GetError() == EWOULDBLOCK) {
151 status = net::WRITE_STATUS_BLOCKED;
152 } else {
153 status = net::WRITE_STATUS_ERROR;
154 }
155 return net::WriteResult(status, rv);
156 }
157
158 // Returns true if the writer buffers and subsequently rewrites data
159 // when an attempt to write results in the underlying socket becoming
160 // write blocked.
161 bool IsWriteBlockedDataBuffered() const override { return true; }
162
163 // Returns true if the network socket is not writable.
164 bool IsWriteBlocked() const override { return !fake_channel_->writable(); }
165
166 // Records that the socket has become writable, for example when an EPOLLOUT
167 // is received or an asynchronous write completes.
168 void SetWritable() override { fake_channel_->SetWritable(true); }
169
170 // Returns the maximum size of the packet which can be written using this
171 // writer for the supplied peer address. This size may actually exceed the
172 // size of a valid QUIC packet.
173 QuicByteCount GetMaxPacketSize(
174 const IPEndPoint& peer_address) const override {
175 return net::kMaxPacketSize;
176 }
177
178 private:
179 FakeTransportChannel* fake_channel_;
180 };
181
182 // Creates a FakePacketWriter for a given QuicConnection instance
183 class FakePacketWriterFactory : public QuicConnection::PacketWriterFactory {
184 public:
185 explicit FakePacketWriterFactory(FakeTransportChannel* channel)
186 : channel_(channel) {}
187 ~FakePacketWriterFactory() override {}
188
189 QuicPacketWriter* Create(QuicConnection* connection) const override {
190 return new FakeQuicPacketWriter(channel_);
191 }
192
193 private:
194 FakeTransportChannel* channel_;
195 };
196
197 // Wrapper for QuicSession and transport channel that stores incoming data
198 class QuicSessionForTest : public QuicSession {
199 public:
200 QuicSessionForTest(scoped_ptr<net::QuicConnection> connection,
201 const net::QuicConfig& config,
202 scoped_ptr<FakeTransportChannel> channel)
203 : QuicSession(std::move(connection), config),
204 channel_(channel.release()) {
205 channel_->SignalReadPacket.connect(
206 this, &QuicSessionForTest::OnChannelReadPacket);
207 }
208
209 // Called when channel has packets to read
210 void OnChannelReadPacket(TransportChannel* channel,
211 const char* data,
212 size_t size,
213 const rtc::PacketTime& packet_time,
214 int flags) {
215 OnReadPacket(data, size);
216 }
217
218 // Called when peer receives incoming stream from another peer
219 void OnIncomingStream(ReliableQuicStream* stream) {
220 stream->SignalDataReceived.connect(this,
221 &QuicSessionForTest::OnDataReceived);
222 last_incoming_stream_ = stream;
223 }
224
225 // Called when peer has data to read from incoming stream
226 void OnDataReceived(net::QuicStreamId id, const char* data, size_t length) {
227 last_received_data_ = std::string(data, length);
228 }
229
230 std::string data() { return last_received_data_; }
231
232 bool has_data() { return data().size() > 0; }
233
234 FakeTransportChannel* channel() { return channel_.get(); }
235
236 ReliableQuicStream* incoming_stream() { return last_incoming_stream_; }
237
238 private:
239 // Transports QUIC packets to/from peer
240 scoped_ptr<FakeTransportChannel> channel_;
241 // Stores data received by peer once it is sent from the other peer
242 std::string last_received_data_ = "";
243 // Handles incoming streams from sender
244 ReliableQuicStream* last_incoming_stream_;
245 };
246
247 // Simulates data transfer between two peers using QUIC
248 class QuicSessionTest : public ::testing::Test,
249 public QuicCryptoClientStream::ProofHandler {
250 public:
251 QuicSessionTest() : quic_helper_(rtc::Thread::Current()) {}
252
253 ~QuicSessionTest() override {}
254
255 // Instantiates |client_peer_| and |server_peer_|
256 void CreateClientAndServerSessions();
257
258 scoped_ptr<QuicSessionForTest> CreateSession(
259 scoped_ptr<FakeTransportChannel> channel,
260 Perspective perspective);
261
262 QuicCryptoClientStream* CreateCryptoClientStream(QuicSessionForTest* session,
263 bool handshake_success);
264 QuicCryptoServerStream* CreateCryptoServerStream(QuicSessionForTest* session,
265 bool handshake_success);
266
267 scoped_ptr<QuicConnection> CreateConnection(FakeTransportChannel* channel,
268 Perspective perspective);
269
270 void StartHandshake(bool client_handshake_success,
271 bool server_handshake_success);
272
273 // Test handshake establishment and sending/receiving of data
274 void TestStreamConnection(QuicSessionForTest* from_session,
275 QuicSessionForTest* to_session);
276 // Test that client and server are not connected after handshake failure
277 void TestDisconnectAfterFailedHandshake();
278
279 // QuicCryptoClientStream::ProofHelper overrides.
280 void OnProofValid(
281 const QuicCryptoClientConfig::CachedState& cached) override {}
282 void OnProofVerifyDetailsAvailable(
283 const ProofVerifyDetails& verify_details) override {}
284
285 protected:
286 QuicConnectionHelper quic_helper_;
287 QuicConfig config_;
288 QuicClock clock_;
289
290 scoped_ptr<QuicSessionForTest> client_peer_;
291 scoped_ptr<QuicSessionForTest> server_peer_;
292 };
293
294 // Initializes "client peer" who begins crypto handshake and "server peer" who
295 // establishes encryption with client
296 void QuicSessionTest::CreateClientAndServerSessions() {
297 scoped_ptr<FakeTransportChannel> channel1(
298 new FakeTransportChannel(nullptr, "channel1", 0));
299 scoped_ptr<FakeTransportChannel> channel2(
300 new FakeTransportChannel(nullptr, "channel2", 0));
301
302 // Prevent channel1->OnReadPacket and channel2->OnReadPacket from calling
303 // themselves in a loop, which causes to future packets to be recursively
304 // consumed while the current thread blocks consumption of current ones
305 channel2->SetAsync(true);
306
307 // Configure peers to send packets to each other
308 channel1->Connect();
309 channel2->Connect();
310 channel1->SetDestination(channel2.get());
311
312 client_peer_ = CreateSession(std::move(channel1), Perspective::IS_CLIENT);
313 server_peer_ = CreateSession(std::move(channel2), Perspective::IS_SERVER);
314 }
315
316 scoped_ptr<QuicSessionForTest> QuicSessionTest::CreateSession(
317 scoped_ptr<FakeTransportChannel> channel,
318 Perspective perspective) {
319 scoped_ptr<QuicConnection> quic_connection =
320 CreateConnection(channel.get(), perspective);
321 return scoped_ptr<QuicSessionForTest>(new QuicSessionForTest(
322 std::move(quic_connection), config_, std::move(channel)));
323 }
324
325 QuicCryptoClientStream* QuicSessionTest::CreateCryptoClientStream(
326 QuicSessionForTest* session,
327 bool handshake_success) {
328 QuicCryptoClientConfig* client_config =
329 new QuicCryptoClientConfig(new FakeProofVerifier(handshake_success));
330 return new QuicCryptoClientStream(
331 kServerId, session, new ProofVerifyContext(), client_config, this);
332 }
333
334 QuicCryptoServerStream* QuicSessionTest::CreateCryptoServerStream(
335 QuicSessionForTest* session,
336 bool handshake_success) {
337 QuicCryptoServerConfig* server_config =
338 new QuicCryptoServerConfig("TESTING", QuicRandom::GetInstance(),
339 new FakeProofSource(handshake_success));
340 // Provide server with serialized config string to prove ownership
341 QuicCryptoServerConfig::ConfigOptions options;
342 QuicServerConfigProtobuf* primary_config = server_config->GenerateConfig(
343 QuicRandom::GetInstance(), &clock_, options);
344 server_config->AddConfig(primary_config, clock_.WallNow());
345 return new QuicCryptoServerStream(server_config, session);
346 }
347
348 scoped_ptr<QuicConnection> QuicSessionTest::CreateConnection(
349 FakeTransportChannel* channel,
350 Perspective perspective) {
351 FakePacketWriterFactory writer_factory(channel);
352
353 IPAddressNumber ip(net::kIPv4AddressSize, 0);
354
355 return scoped_ptr<QuicConnection>(new QuicConnection(
356 0, net::IPEndPoint(ip, 0), &quic_helper_, writer_factory,
357 true /* owns_writer */, perspective, net::QuicSupportedVersions()));
358 }
359
360 void QuicSessionTest::StartHandshake(bool client_handshake_success,
361 bool server_handshake_success) {
362 server_peer_->StartServerHandshake(
363 CreateCryptoServerStream(server_peer_.get(), server_handshake_success));
364 client_peer_->StartClientHandshake(
365 CreateCryptoClientStream(client_peer_.get(), client_handshake_success));
366 }
367
368 void QuicSessionTest::TestStreamConnection(QuicSessionForTest* from_session,
369 QuicSessionForTest* to_session) {
370 // Wait for crypto handshake to finish then check if encryption established
371 ASSERT_TRUE_WAIT(from_session->IsCryptoHandshakeConfirmed() &&
372 to_session->IsCryptoHandshakeConfirmed(),
373 kTimeoutMs);
374
375 EXPECT_TRUE(from_session->IsEncryptionEstablished());
376 EXPECT_TRUE(to_session->IsEncryptionEstablished());
pthatcher1 2016/02/03 23:27:24 These should be ASSERT_TRUE
mikescarlett 2016/02/05 21:10:29 Agreed.
377
378 string from_out;
379 string to_out;
pthatcher1 2016/02/03 23:27:23 Should this be from_key and to_key?
mikescarlett 2016/02/05 21:10:29 Done. That is more descriptive.
380
381 bool from_success = from_session->ExportKeyingMaterial(
382 kExporterLabel, kExporterContext, kExporterContextLen, &from_out);
383 EXPECT_TRUE(from_success);
384 bool to_success = to_session->ExportKeyingMaterial(
385 kExporterLabel, kExporterContext, kExporterContextLen, &to_out);
386 EXPECT_TRUE(to_success);
pthatcher1 2016/02/03 23:27:24 I think these should be ASSERT_TRUEs, and then you
mikescarlett 2016/02/05 21:10:29 Agreed and done.
387
388 if (!from_success || !to_success) {
389 return;
390 }
391
392 EXPECT_EQ(from_out.size(), kExporterContextLen);
393 EXPECT_EQ(0, from_out.compare(to_out));
394
395 // Now we can establish encrypted outgoing stream
396 ReliableQuicStream* outgoing_stream =
397 from_session->CreateOutgoingDynamicStream(kDefaultPriority);
398 ASSERT_NE(nullptr, outgoing_stream);
399 EXPECT_TRUE(from_session->HasOpenDynamicStreams());
400
401 outgoing_stream->SignalDataReceived.connect(
402 from_session, &QuicSessionForTest::OnDataReceived);
403 to_session->SignalIncomingStream.connect(
404 to_session, &QuicSessionForTest::OnIncomingStream);
405
406 // Send a test message from peer 1 to peer 2
407 const char kTestMessage[] = "Hello, World!";
408 outgoing_stream->Write(kTestMessage, strlen(kTestMessage));
409
410 // Wait for peer 2 to receive messages
411 ASSERT_TRUE_WAIT(to_session->has_data(), kTimeoutMs);
412
413 ReliableQuicStream* incoming = to_session->incoming_stream();
414 ASSERT_TRUE(incoming);
415 EXPECT_TRUE(to_session->HasOpenDynamicStreams());
416
417 EXPECT_EQ(0, to_session->data().compare(kTestMessage));
418
419 // Send a test message from peer 2 to peer 1
420 const char kTestResponse[] = "Response";
421 incoming->Write(kTestResponse, strlen(kTestResponse));
422
423 // Wait for peer 1 to receive messages
424 ASSERT_TRUE_WAIT(from_session->has_data(), kTimeoutMs);
425
426 EXPECT_EQ(0, from_session->data().compare(kTestResponse));
427 }
428
429 // Client and server should disconnect when proof verification fails
430 void QuicSessionTest::TestDisconnectAfterFailedHandshake() {
431 EXPECT_TRUE_WAIT(!client_peer_->connection()->connected(), kTimeoutMs);
432 EXPECT_TRUE_WAIT(!server_peer_->connection()->connected(), kTimeoutMs);
433
434 EXPECT_FALSE(client_peer_->IsEncryptionEstablished());
435 EXPECT_FALSE(client_peer_->IsCryptoHandshakeConfirmed());
436
437 EXPECT_FALSE(server_peer_->IsEncryptionEstablished());
438 EXPECT_FALSE(server_peer_->IsCryptoHandshakeConfirmed());
439 }
440
441 // Establish encryption then send message from client to server
442 TEST_F(QuicSessionTest, ClientToServer) {
443 CreateClientAndServerSessions();
444 StartHandshake(true, true);
445 TestStreamConnection(client_peer_.get(), server_peer_.get());
446 }
447
448 // Establish encryption then send message from server to client
449 TEST_F(QuicSessionTest, ServerToClient) {
450 CreateClientAndServerSessions();
451 StartHandshake(true, true);
452 TestStreamConnection(server_peer_.get(), client_peer_.get());
453 }
454
455 // Make client fail to verify proof from server
456 TEST_F(QuicSessionTest, ClientRejection) {
457 CreateClientAndServerSessions();
458 StartHandshake(false, true);
459 TestDisconnectAfterFailedHandshake();
460 }
461
462 // Make server fail to give proof to client
463 TEST_F(QuicSessionTest, ServerRejection) {
464 CreateClientAndServerSessions();
465 StartHandshake(true, false);
466 TestDisconnectAfterFailedHandshake();
467 }
468
469 // Test that data streams are not created before handshake
470 TEST_F(QuicSessionTest, CannotCreateDataStreamBeforeHandshake) {
471 CreateClientAndServerSessions();
472 EXPECT_EQ(nullptr, server_peer_->CreateOutgoingDynamicStream(5));
473 EXPECT_EQ(nullptr, client_peer_->CreateOutgoingDynamicStream(5));
474 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698