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

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

Powered by Google App Engine
This is Rietveld 408576698