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

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: Modify QuicSession unit test string comparison asserts 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"
Taylor Brandstetter 2016/02/06 00:22:45 nit: include order
mikescarlett 2016/02/06 02:14:09 Done.
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
Taylor Brandstetter 2016/02/06 00:22:44 nit: Use periods at the end of comments (it took m
mikescarlett 2016/02/06 02:14:09 Done.
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() {}
Taylor Brandstetter 2016/02/06 00:22:45 Is there a reason why this destructor doesn't use
mikescarlett 2016/02/06 02:14:09 I removed the empty destructors since they don't d
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()) {
Taylor Brandstetter 2016/02/06 00:22:44 Use std::move(channel).
mikescarlett 2016/02/06 02:14:09 Done.
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_ = "";
Taylor Brandstetter 2016/02/06 00:22:45 Does '= ""' have a purpose here?
mikescarlett 2016/02/06 02:14:09 Removed '= ""' since it doesn't do anything.
243 // Handles incoming streams from sender
244 ReliableQuicStream* last_incoming_stream_;
Taylor Brandstetter 2016/02/06 00:22:44 This variable needs to be default initialized. Re
mikescarlett 2016/02/06 02:14:09 Done.
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 bool owns_writer = true;
355
356 return scoped_ptr<QuicConnection>(new QuicConnection(
357 0, net::IPEndPoint(ip, 0), &quic_helper_, writer_factory, owns_writer,
358 perspective, net::QuicSupportedVersions()));
359 }
360
361 void QuicSessionTest::StartHandshake(bool client_handshake_success,
362 bool server_handshake_success) {
363 server_peer_->StartServerHandshake(
364 CreateCryptoServerStream(server_peer_.get(), server_handshake_success));
365 client_peer_->StartClientHandshake(
366 CreateCryptoClientStream(client_peer_.get(), client_handshake_success));
367 }
368
369 void QuicSessionTest::TestStreamConnection(QuicSessionForTest* from_session,
370 QuicSessionForTest* to_session) {
371 // Wait for crypto handshake to finish then check if encryption established
372 ASSERT_TRUE_WAIT(from_session->IsCryptoHandshakeConfirmed() &&
373 to_session->IsCryptoHandshakeConfirmed(),
374 kTimeoutMs);
375
376 ASSERT_TRUE(from_session->IsEncryptionEstablished());
377 ASSERT_TRUE(to_session->IsEncryptionEstablished());
378
379 string from_key;
380 string to_key;
381
382 bool from_success = from_session->ExportKeyingMaterial(
383 kExporterLabel, kExporterContext, kExporterContextLen, &from_key);
384 ASSERT_TRUE(from_success);
385 bool to_success = to_session->ExportKeyingMaterial(
386 kExporterLabel, kExporterContext, kExporterContextLen, &to_key);
387 ASSERT_TRUE(to_success);
388
389 EXPECT_EQ(from_key.size(), kExporterContextLen);
390 EXPECT_EQ(from_key, to_key);
391
392 // Now we can establish encrypted outgoing stream
393 ReliableQuicStream* outgoing_stream =
394 from_session->CreateOutgoingDynamicStream(kDefaultPriority);
Taylor Brandstetter 2016/02/06 00:22:45 Where is this object freed? It does say "owned by
mikescarlett 2016/02/06 02:14:09 I am concluding that Chromium's documentation migh
395 ASSERT_NE(nullptr, outgoing_stream);
396 EXPECT_TRUE(from_session->HasOpenDynamicStreams());
397
398 outgoing_stream->SignalDataReceived.connect(
399 from_session, &QuicSessionForTest::OnDataReceived);
400 to_session->SignalIncomingStream.connect(
401 to_session, &QuicSessionForTest::OnIncomingStream);
402
403 // Send a test message from peer 1 to peer 2
404 const char kTestMessage[] = "Hello, World!";
405 outgoing_stream->Write(kTestMessage, strlen(kTestMessage));
406
407 // Wait for peer 2 to receive messages
408 ASSERT_TRUE_WAIT(to_session->has_data(), kTimeoutMs);
409
410 ReliableQuicStream* incoming = to_session->incoming_stream();
411 ASSERT_TRUE(incoming);
412 EXPECT_TRUE(to_session->HasOpenDynamicStreams());
413
414 EXPECT_EQ(to_session->data(), kTestMessage);
415
416 // Send a test message from peer 2 to peer 1
417 const char kTestResponse[] = "Response";
418 incoming->Write(kTestResponse, strlen(kTestResponse));
419
420 // Wait for peer 1 to receive messages
421 ASSERT_TRUE_WAIT(from_session->has_data(), kTimeoutMs);
422
423 EXPECT_EQ(from_session->data(), kTestResponse);
424 }
425
426 // Client and server should disconnect when proof verification fails
427 void QuicSessionTest::TestDisconnectAfterFailedHandshake() {
428 EXPECT_TRUE_WAIT(!client_peer_->connection()->connected(), kTimeoutMs);
429 EXPECT_TRUE_WAIT(!server_peer_->connection()->connected(), kTimeoutMs);
430
431 EXPECT_FALSE(client_peer_->IsEncryptionEstablished());
432 EXPECT_FALSE(client_peer_->IsCryptoHandshakeConfirmed());
433
434 EXPECT_FALSE(server_peer_->IsEncryptionEstablished());
435 EXPECT_FALSE(server_peer_->IsCryptoHandshakeConfirmed());
436 }
437
438 // Establish encryption then send message from client to server
439 TEST_F(QuicSessionTest, ClientToServer) {
440 CreateClientAndServerSessions();
441 StartHandshake(true, true);
442 TestStreamConnection(client_peer_.get(), server_peer_.get());
443 }
444
445 // Establish encryption then send message from server to client
446 TEST_F(QuicSessionTest, ServerToClient) {
447 CreateClientAndServerSessions();
448 StartHandshake(true, true);
449 TestStreamConnection(server_peer_.get(), client_peer_.get());
450 }
451
452 // Make client fail to verify proof from server
453 TEST_F(QuicSessionTest, ClientRejection) {
454 CreateClientAndServerSessions();
455 StartHandshake(false, true);
456 TestDisconnectAfterFailedHandshake();
457 }
458
459 // Make server fail to give proof to client
460 TEST_F(QuicSessionTest, ServerRejection) {
461 CreateClientAndServerSessions();
462 StartHandshake(true, false);
463 TestDisconnectAfterFailedHandshake();
464 }
465
466 // Test that data streams are not created before handshake
467 TEST_F(QuicSessionTest, CannotCreateDataStreamBeforeHandshake) {
468 CreateClientAndServerSessions();
469 EXPECT_EQ(nullptr, server_peer_->CreateOutgoingDynamicStream(5));
470 EXPECT_EQ(nullptr, client_peer_->CreateOutgoingDynamicStream(5));
471 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698