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

Side by Side Diff: net/quic/quartc/quartc_session_test.cc

Issue 2324833004: Define Stable API for WebRTC/Quartc (Closed)
Patch Set: Fix the memory leak. Created 4 years, 1 month 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 // Copyright (c) 2016 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 #include "net/quic/quartc/quartc_session.h"
6
7 #include "base/bind.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/run_loop.h"
10 #include "base/threading/thread_task_runner_handle.h"
11 #include "net/base/ip_endpoint.h"
12 #include "net/quic/core/crypto/crypto_server_config_protobuf.h"
13 #include "net/quic/core/crypto/proof_source.h"
14 #include "net/quic/core/crypto/proof_verifier.h"
15 #include "net/quic/core/crypto/quic_crypto_client_config.h"
16 #include "net/quic/core/crypto/quic_crypto_server_config.h"
17 #include "net/quic/core/crypto/quic_random.h"
18 #include "net/quic/core/quic_crypto_client_stream.h"
19 #include "net/quic/core/quic_crypto_server_stream.h"
20 #include "net/quic/core/quic_simple_buffer_allocator.h"
21 #include "net/quic/quartc/quartc_alarm_factory.h"
22 #include "net/quic/quartc/quartc_packet_writer.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24
25 namespace net {
26 namespace test {
27 namespace {
28
29 static const char kExporterLabel[] = "label";
30 static const uint8_t kExporterContext[] = "context";
31 static const size_t kExporterContextLen = sizeof(kExporterContext);
32 static const size_t kOutputKeyLength = 20;
33 static QuartcStreamInterface::WriteParameters kDefaultWriteParam;
34 static QuartcSessionInterface::OutgoingStreamParameters kDefaultStreamParam;
35 static QuicByteCount kDefaultMaxPacketSize = 1200;
36
37 // Use the MessageLoop to simulate the asynchronous P2P communication. The
38 // RunLoop is used for handling the posted tasks.
39 void SetTimedOutAndQuitLoop(const base::WeakPtr<bool> timed_out,
40 const base::Closure& quit_loop_func) {
41 if (timed_out) {
42 *timed_out = true;
43 quit_loop_func.Run();
44 }
45 }
46
47 bool RunLoopWithTimeout() {
48 base::RunLoop rl;
49 bool timed_out = false;
50 base::WeakPtrFactory<bool> timed_out_weak_factory(&timed_out);
51 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
52 FROM_HERE,
53 base::Bind(&SetTimedOutAndQuitLoop, timed_out_weak_factory.GetWeakPtr(),
54 rl.QuitClosure()),
55 base::TimeDelta::FromMilliseconds(500));
56 rl.RunUntilIdle();
57 return !timed_out;
58 }
59
60 // Used by QuicCryptoServerConfig to provide server credentials, returning a
61 // canned response equal to |success|.
62 class FakeProofSource : public net::ProofSource {
63 public:
64 explicit FakeProofSource(bool success) : success_(success) {}
65
66 // ProofSource override.
67 bool GetProof(const IPAddress& server_ip,
68 const std::string& hostname,
69 const std::string& server_config,
70 net::QuicVersion quic_version,
71 base::StringPiece chlo_hash,
72 scoped_refptr<net::ProofSource::Chain>* out_certs,
73 std::string* out_signature,
74 std::string* out_leaf_cert_sct) override {
75 if (success_) {
76 std::vector<std::string> certs;
77 certs.push_back("Required to establish handshake");
78 *out_certs = new ProofSource::Chain(certs);
79 *out_signature = "Signature";
80 *out_leaf_cert_sct = "Time";
81 }
82 return success_;
83 }
84
85 void GetProof(const net::IPAddress& server_ip,
86 const std::string& hostname,
87 const std::string& server_config,
88 net::QuicVersion quic_version,
89 base::StringPiece chlo_hash,
90 std::unique_ptr<Callback> callback) override {
91 LOG(INFO) << "GetProof() providing dummy credentials for insecure QUIC";
92 }
93
94 private:
95 // Whether or not obtaining proof source succeeds.
96 bool success_;
97 };
98
99 // Used by QuicCryptoClientConfig to verify server credentials, returning a
100 // canned response of QUIC_SUCCESS if |success| is true.
101 class FakeProofVerifier : public net::ProofVerifier {
102 public:
103 explicit FakeProofVerifier(bool success) : success_(success) {}
104
105 // ProofVerifier override
106 net::QuicAsyncStatus VerifyProof(
107 const std::string& hostname,
108 const uint16_t port,
109 const std::string& server_config,
110 net::QuicVersion quic_version,
111 base::StringPiece chlo_hash,
112 const std::vector<std::string>& certs,
113 const std::string& cert_sct,
114 const std::string& signature,
115 const ProofVerifyContext* context,
116 std::string* error_details,
117 std::unique_ptr<net::ProofVerifyDetails>* verify_details,
118 std::unique_ptr<net::ProofVerifierCallback> callback) override {
119 return success_ ? net::QUIC_SUCCESS : net::QUIC_FAILURE;
120 }
121
122 net::QuicAsyncStatus VerifyCertChain(
123 const std::string& hostname,
124 const std::vector<std::string>& certs,
125 const net::ProofVerifyContext* context,
126 std::string* error_details,
127 std::unique_ptr<net::ProofVerifyDetails>* details,
128 std::unique_ptr<net::ProofVerifierCallback> callback) override {
129 LOG(INFO) << "VerifyProof() ignoring credentials and returning success";
130 return success_ ? net::QUIC_SUCCESS : net::QUIC_FAILURE;
131 }
132
133 private:
134 // Whether or not proof verification succeeds.
135 bool success_;
136 };
137
138 // Used by the FakeTransportChannel.
139 class FakeTransportChannelObserver {
140 public:
141 // Called when the other peer is trying to send message.
142 virtual void OnTransportChannelReadPacket(const std::string& data) = 0;
143 };
144
145 // Simulate the P2P communication transport. Used by the
146 // QuartcSessionInterface::Transport.
147 class FakeTransportChannel {
148 public:
149 void SetDestination(FakeTransportChannel* dest) {
150 if (!dest_) {
151 dest_ = dest;
152 dest_->SetDestination(this);
153 }
154 }
155
156 int SendPacket(const char* data, size_t len) {
157 // If the destination is not set.
158 if (!dest_) {
159 return -1;
160 }
161 if (async_) {
162 base::ThreadTaskRunnerHandle::Get()->PostTask(
163 FROM_HERE,
164 base::Bind(&FakeTransportChannel::send, base::Unretained(this),
165 std::string(data, len)));
166 } else {
167 send(std::string(data, len));
168 }
169 return static_cast<int>(len);
170 }
171
172 void send(const std::string& data) {
173 dest_->observer()->OnTransportChannelReadPacket(data);
174 }
175
176 FakeTransportChannelObserver* observer() { return observer_; }
177
178 void SetObserver(FakeTransportChannelObserver* observer) {
179 observer_ = observer;
180 }
181
182 void SetAsync(bool async) { async_ = async; }
183
184 private:
185 // The writing destination of this channel.
186 FakeTransportChannel* dest_ = nullptr;
187 // The observer of this channel. Called when the received the data.
188 FakeTransportChannelObserver* observer_ = nullptr;
189 // If async, will send packets by "Post"-ing to message queue instead of
190 // synchronously "Send"-ing.
191 bool async_ = false;
192 };
193
194 // Used by the QuartcPacketWriter.
195 class FakeTransport : public QuartcSessionInterface::PacketTransport {
196 public:
197 FakeTransport(FakeTransportChannel* channel) : channel_(channel) {}
198
199 bool CanWrite() override { return true; }
200
201 int Write(const char* buffer, size_t buf_len) override {
202 DCHECK(channel_);
203 return channel_->SendPacket(buffer, buf_len);
204 }
205
206 private:
207 FakeTransportChannel* channel_;
208 };
209
210 class FakeQuartcSessionDelegate : public QuartcSessionInterface::Delegate {
211 public:
212 FakeQuartcSessionDelegate(QuartcStreamInterface::Delegate* stream_delegate)
213 : stream_delegate_(stream_delegate) {}
214 // Called when peers have established forward-secure encryption
215 void OnCryptoHandshakeComplete() override {
216 LOG(INFO) << "Crypto handshake complete!";
217 }
218 // Called when connection closes locally, or remotely by peer.
219 void OnConnectionClosed(int error_code, bool from_remote) override {
220 connected_ = false;
221 }
222 // Called when an incoming QUIC stream is created.
223 void OnIncomingStream(QuartcStreamInterface* quartc_stream) override {
224 last_incoming_stream_ = quartc_stream;
225 last_incoming_stream_->SetDelegate(stream_delegate_);
226 }
227
228 QuartcStreamInterface* incoming_stream() { return last_incoming_stream_; }
229
230 bool connected() { return connected_; }
231
232 private:
233 QuartcStreamInterface* last_incoming_stream_;
234 bool connected_ = true;
235 QuartcStream::Delegate* stream_delegate_;
236 };
237
238 class FakeQuartcStreamDelegate : public QuartcStreamInterface::Delegate {
239 public:
240 void OnReceived(QuartcStreamInterface* stream,
241 const char* data,
242 size_t size) override {
243 last_received_data_ = std::string(data, size);
244 }
245
246 void OnClose(QuartcStreamInterface* stream, int error_code) override {}
247
248 void OnBufferedAmountDecrease(QuartcStreamInterface* stream) override {}
249
250 std::string data() { return last_received_data_; }
251
252 private:
253 std::string last_received_data_;
254 };
255
256 class QuartcSessionForTest : public QuartcSession,
257 public FakeTransportChannelObserver {
258 public:
259 QuartcSessionForTest(std::unique_ptr<QuicConnection> connection,
260 const QuicConfig& config,
261 const std::string& remote_fingerprint_value,
262 Perspective perspective,
263 QuicConnectionHelperInterface* helper)
264 : QuartcSession(std::move(connection),
265 config,
266 remote_fingerprint_value,
267 perspective,
268 helper) {
269 stream_delegate_.reset(new FakeQuartcStreamDelegate);
270 session_delegate_.reset(
271 new FakeQuartcSessionDelegate(stream_delegate_.get()));
272
273 SetDelegate(session_delegate_.get());
274 }
275
276 // QuartcPacketWriter override.
277 void OnTransportChannelReadPacket(const std::string& data) override {
278 OnTransportReceived(data.c_str(), data.length());
279 }
280
281 std::string data() { return stream_delegate_->data(); }
282
283 bool has_data() { return !data().empty(); }
284
285 FakeQuartcSessionDelegate* session_delegate() {
286 return session_delegate_.get();
287 }
288
289 FakeQuartcStreamDelegate* stream_delegate() { return stream_delegate_.get(); }
290
291 private:
292 std::unique_ptr<FakeQuartcStreamDelegate> stream_delegate_;
293 std::unique_ptr<FakeQuartcSessionDelegate> session_delegate_;
294 };
295
296 class QuartcSessionTest : public ::testing::Test,
297 public QuicConnectionHelperInterface {
298 public:
299 ~QuartcSessionTest() override {}
300
301 void Init() {
302 client_channel_.reset(new FakeTransportChannel);
303 server_channel_.reset(new FakeTransportChannel);
304 // Make the channel asynchronous so that two peer will not keep calling each
305 // other when they exchange information.
306 client_channel_->SetAsync(true);
307 client_channel_->SetDestination(server_channel_.get());
308
309 client_transport_.reset(new FakeTransport(client_channel_.get()));
310 server_transport_.reset(new FakeTransport(server_channel_.get()));
311
312 client_writer_.reset(
313 new QuartcPacketWriter(client_transport_.get(), kDefaultMaxPacketSize));
314 server_writer_.reset(
315 new QuartcPacketWriter(server_transport_.get(), kDefaultMaxPacketSize));
316 }
317
318 // The parameters are used to control whether the handshake will success or
319 // not.
320 void CreateClientAndServerSessions(bool client_handshake_success = true,
321 bool server_handshake_success = true) {
322 Init();
323 client_peer_ = CreateSession(Perspective::IS_CLIENT);
324 server_peer_ = CreateSession(Perspective::IS_SERVER);
325
326 client_channel_->SetObserver(client_peer_.get());
327 server_channel_->SetObserver(server_peer_.get());
328
329 client_peer_->SetClientCryptoConfig(
330 new QuicCryptoClientConfig(std::unique_ptr<ProofVerifier>(
331 new FakeProofVerifier(client_handshake_success))));
332
333 QuicCryptoServerConfig* server_config = new QuicCryptoServerConfig(
334 "TESTING", QuicRandom::GetInstance(),
335 std::unique_ptr<FakeProofSource>(
336 new FakeProofSource(server_handshake_success)));
337 // Provide server with serialized config string to prove ownership.
338 QuicCryptoServerConfig::ConfigOptions options;
339 std::unique_ptr<QuicServerConfigProtobuf> primary_config(
340 server_config->GenerateConfig(QuicRandom::GetInstance(), &clock_,
341 options));
342 std::unique_ptr<CryptoHandshakeMessage> message(
343 server_config->AddConfig(std::move(primary_config), clock_.WallNow()));
344
345 server_peer_->SetServerCryptoConfig(server_config);
346 }
347
348 std::unique_ptr<QuartcSessionForTest> CreateSession(Perspective perspective) {
349 std::unique_ptr<QuicConnection> quic_connection =
350 CreateConnection(perspective);
351 std::string remote_fingerprint_value = "value";
352 QuicConfig config;
353 return std::unique_ptr<QuartcSessionForTest>(
354 new QuartcSessionForTest(std::move(quic_connection), config,
355 remote_fingerprint_value, perspective, this));
356 }
357
358 std::unique_ptr<QuicConnection> CreateConnection(Perspective perspective) {
359 QuartcPacketWriter* writer = perspective == Perspective::IS_CLIENT
360 ? client_writer_.get()
361 : server_writer_.get();
362 IPAddress ip(0, 0, 0, 0);
363 bool owns_writer = false;
364 alarm_factory_.reset(new QuartcAlarmFactory(
365 base::ThreadTaskRunnerHandle::Get().get(), GetClock()));
366 return std::unique_ptr<QuicConnection>(new QuicConnection(
367 0, IPEndPoint(ip, 0), this /*QuicConnectionHelperInterface*/,
368 alarm_factory_.get(), writer, owns_writer, perspective,
369 AllSupportedVersions()));
370 }
371 void StartHandshake() {
372 server_peer_->StartCryptoHandshake();
373 client_peer_->StartCryptoHandshake();
374 RunLoopWithTimeout();
375 }
376
377 // Test handshake establishment and sending/receiving of data for two
378 // directions.
379 void TestStreamConnection() {
380 ASSERT_TRUE(server_peer_->IsCryptoHandshakeConfirmed() &&
381 client_peer_->IsCryptoHandshakeConfirmed());
382 ASSERT_TRUE(server_peer_->IsEncryptionEstablished());
383 ASSERT_TRUE(client_peer_->IsEncryptionEstablished());
384
385 uint8_t server_key[kOutputKeyLength];
386 uint8_t client_key[kOutputKeyLength];
387 bool use_context = true;
388 bool server_success = server_peer_->ExportKeyingMaterial(
389 kExporterLabel, kExporterContext, kExporterContextLen, use_context,
390 server_key, kOutputKeyLength);
391 ASSERT_TRUE(server_success);
392 bool client_success = client_peer_->ExportKeyingMaterial(
393 kExporterLabel, kExporterContext, kExporterContextLen, use_context,
394 client_key, kOutputKeyLength);
395 ASSERT_TRUE(client_success);
396 EXPECT_EQ(0, memcmp(server_key, client_key, sizeof(server_key)));
397
398 // Now we can establish encrypted outgoing stream.
399 QuartcStreamInterface* outgoing_stream =
400 server_peer_->CreateOutgoingStream(kDefaultStreamParam);
401 ASSERT_NE(nullptr, outgoing_stream);
402 EXPECT_TRUE(server_peer_->HasOpenDynamicStreams());
403
404 outgoing_stream->SetDelegate(server_peer_->stream_delegate());
405
406 // Send a test message from peer 1 to peer 2.
407 const char kTestMessage[] = "Hello";
408 outgoing_stream->Write(kTestMessage, strlen(kTestMessage),
409 kDefaultWriteParam);
410 RunLoopWithTimeout();
411
412 // Wait for peer 2 to receive messages.
413 ASSERT_TRUE(client_peer_->has_data());
414
415 QuartcStreamInterface* incoming =
416 client_peer_->session_delegate()->incoming_stream();
417 ASSERT_TRUE(incoming);
418 EXPECT_TRUE(client_peer_->HasOpenDynamicStreams());
419
420 EXPECT_EQ(client_peer_->data(), kTestMessage);
421 // Send a test message from peer 2 to peer 1.
422 const char kTestResponse[] = "Response";
423 incoming->Write(kTestResponse, strlen(kTestResponse), kDefaultWriteParam);
424 RunLoopWithTimeout();
425 // Wait for peer 1 to receive messages.
426 ASSERT_TRUE(server_peer_->has_data());
427
428 EXPECT_EQ(server_peer_->data(), kTestResponse);
429 }
430
431 // Test that client and server are not connected after handshake failure.
432 void TestDisconnectAfterFailedHandshake() {
433 EXPECT_TRUE(!client_peer_->session_delegate()->connected());
434 EXPECT_TRUE(!server_peer_->session_delegate()->connected());
435
436 EXPECT_FALSE(client_peer_->IsEncryptionEstablished());
437 EXPECT_FALSE(client_peer_->IsCryptoHandshakeConfirmed());
438
439 EXPECT_FALSE(server_peer_->IsEncryptionEstablished());
440 EXPECT_FALSE(server_peer_->IsCryptoHandshakeConfirmed());
441 }
442
443 const QuicClock* GetClock() const override { return &clock_; }
444
445 QuicRandom* GetRandomGenerator() override {
446 return QuicRandom::GetInstance();
447 }
448
449 QuicBufferAllocator* GetBufferAllocator() override {
450 return &buffer_allocator_;
451 }
452
453 protected:
454 std::unique_ptr<QuicAlarmFactory> alarm_factory_;
455 SimpleBufferAllocator buffer_allocator_;
456 QuicClock clock_;
457
458 std::unique_ptr<FakeTransportChannel> client_channel_;
459 std::unique_ptr<FakeTransportChannel> server_channel_;
460 std::unique_ptr<FakeTransport> client_transport_;
461 std::unique_ptr<FakeTransport> server_transport_;
462 std::unique_ptr<QuartcPacketWriter> client_writer_;
463 std::unique_ptr<QuartcPacketWriter> server_writer_;
464 std::unique_ptr<QuartcSessionForTest> client_peer_;
465 std::unique_ptr<QuartcSessionForTest> server_peer_;
466 };
467
468 TEST_F(QuartcSessionTest, StreamConnection) {
469 CreateClientAndServerSessions();
470 StartHandshake();
471 TestStreamConnection();
472 }
473
474 TEST_F(QuartcSessionTest, ClientRejection) {
475 CreateClientAndServerSessions(false /*client_handshake_success*/,
476 true /*server_handshake_success*/);
477 StartHandshake();
478 TestDisconnectAfterFailedHandshake();
479 }
480
481 TEST_F(QuartcSessionTest, ServerRejection) {
482 CreateClientAndServerSessions(true /*client_handshake_success*/,
483 false /*server_handshake_success*/);
484 StartHandshake();
485 TestDisconnectAfterFailedHandshake();
486 }
487
488 // Test that data streams are not created before handshake.
489 TEST_F(QuartcSessionTest, CannotCreateDataStreamBeforeHandshake) {
490 CreateClientAndServerSessions();
491 EXPECT_EQ(nullptr, server_peer_->CreateOutgoingStream(kDefaultStreamParam));
492 EXPECT_EQ(nullptr, client_peer_->CreateOutgoingStream(kDefaultStreamParam));
493 }
494
495 TEST_F(QuartcSessionTest, CloseQuartcStream) {
496 CreateClientAndServerSessions();
497 StartHandshake();
498 ASSERT_TRUE(client_peer_->IsCryptoHandshakeConfirmed() &&
499 server_peer_->IsCryptoHandshakeConfirmed());
500 QuartcStreamInterface* stream =
501 client_peer_->CreateOutgoingStream(kDefaultStreamParam);
502 ASSERT_NE(nullptr, stream);
503
504 uint32_t id = stream->stream_id();
505 EXPECT_FALSE(client_peer_->IsClosedStream(id));
506 stream->SetDelegate(client_peer_->stream_delegate());
507 stream->Close();
508 EXPECT_TRUE(client_peer_->IsClosedStream(id));
509 }
510
511 } // namespace
512 } // namespace test
513 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698