Chromium Code Reviews| OLD | NEW |
|---|---|
| (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/quictransportchannel.h" | |
| 12 | |
| 13 #include <set> | |
| 14 #include <string> | |
| 15 #include <vector> | |
| 16 | |
| 17 #include "webrtc/base/common.h" | |
| 18 #include "webrtc/base/gunit.h" | |
| 19 #include "webrtc/base/scoped_ptr.h" | |
| 20 #include "webrtc/base/sslidentity.h" | |
| 21 #include "webrtc/p2p/base/faketransportcontroller.h" | |
| 22 | |
| 23 using cricket::ConnectionRole; | |
| 24 using cricket::IceRole; | |
| 25 using cricket::QuicTransportChannel; | |
| 26 using cricket::TransportChannel; | |
| 27 using cricket::TransportDescription; | |
| 28 | |
| 29 // Timeout in milliseconds for asynchronous operations in unit tests. | |
| 30 const int kTimeoutMs = 1000; | |
| 31 | |
| 32 // Export keying material parameters. | |
| 33 const char kExporterLabel[] = "label"; | |
| 34 const uint8_t kExporterContext[] = "context"; | |
| 35 const size_t kExporterContextLength = sizeof(kExporterContext); | |
| 36 const size_t kOutputKeyLength = 20; | |
| 37 | |
| 38 // Packet size for SRTP. | |
| 39 const size_t kPacketSize = 100; | |
| 40 | |
| 41 // Indicates channel has no write error. | |
| 42 const int kNoWriteError = 0; | |
| 43 | |
| 44 // ICE parameters. | |
| 45 const char kIceUfrag[] = "TESTICEUFRAG0001"; | |
| 46 const char kIcePwd[] = "TESTICEPWD00000000000001"; | |
| 47 | |
| 48 // QUIC packet parameters. | |
| 49 const net::IPAddressNumber kIpAddress(net::kIPv4AddressSize, 0); | |
| 50 const net::IPEndPoint kIpEndpoint(kIpAddress, 0); | |
| 51 | |
| 52 // Detects incoming RTP packets. | |
| 53 bool IsRtpLeadByte(uint8_t b) { | |
| 54 return (b & 0xC0) == 0x80; | |
| 55 } | |
| 56 // Detects incoming QUIC packets. | |
| 57 bool IsQuicLeadByte(uint8_t b) { | |
| 58 return (b & 0x80) == 0; | |
| 59 } | |
| 60 | |
| 61 // Maps SSL role to ICE connection role. The peer with a client role is assumed | |
| 62 // to be the one who initiates the connection. | |
| 63 ConnectionRole SslRoleToConnectionRole(rtc::SSLRole ssl_role) { | |
| 64 return (ssl_role == rtc::SSL_CLIENT) ? cricket::CONNECTIONROLE_ACTIVE | |
| 65 : cricket::CONNECTIONROLE_PASSIVE; | |
| 66 } | |
| 67 | |
| 68 // Allows cricket::FakeTransportChannel to simulate write blocked | |
| 69 // and write error states. | |
| 70 // TODO(mikescarlett): Add this functionality to cricket::FakeTransportChannel. | |
| 71 class FakeTransportChannel : public cricket::FakeTransportChannel { | |
| 72 public: | |
| 73 FakeTransportChannel(const std::string& name, int component) | |
| 74 : cricket::FakeTransportChannel(name, component), error_(kNoWriteError) {} | |
| 75 int GetError() override { return error_; } | |
| 76 void SetError(int error) { error_ = error; } | |
| 77 int SendPacket(const char* data, | |
| 78 size_t len, | |
| 79 const rtc::PacketOptions& options, | |
| 80 int flags) override { | |
| 81 if (error_ == kNoWriteError) { | |
| 82 return cricket::FakeTransportChannel::SendPacket(data, len, options, | |
| 83 flags); | |
| 84 } | |
| 85 return -1; | |
| 86 } | |
| 87 | |
| 88 private: | |
| 89 int error_; | |
| 90 }; | |
| 91 | |
| 92 // Peer who establishes a handshake using a QuicTransportChannel, which wraps | |
| 93 // a FakeTransportChannel to simulate network connectivity and ICE negotiation. | |
| 94 class QuicTestPeer : public sigslot::has_slots<> { | |
| 95 public: | |
| 96 explicit QuicTestPeer(const std::string& name) | |
| 97 : name_(name), | |
| 98 bytes_sent_(0), | |
| 99 fake_channel_(name_, 0), | |
| 100 quic_channel_(&fake_channel_) { | |
| 101 quic_channel_.SignalReadPacket.connect( | |
| 102 this, &QuicTestPeer::OnTransportChannelReadPacket); | |
| 103 fake_channel_.SetAsync(true); | |
| 104 SetLocalCertificate(); | |
| 105 } | |
| 106 | |
| 107 // Connects |fake_channel_| to that of the other peer. | |
| 108 void Connect(QuicTestPeer* peer) { | |
| 109 fake_channel_.Connect(); | |
| 110 peer->fake_channel_.Connect(); | |
| 111 fake_channel_.SetDestination(&peer->fake_channel_); | |
| 112 } | |
| 113 | |
| 114 // Disconnects |fake_channel_|. | |
| 115 void Disconnect() { fake_channel_.SetDestination(nullptr); } | |
| 116 | |
| 117 // Simulates the fingerprint exchange and ICE parameter negotiation | |
| 118 // which is done before QUIC handshake is started. Peer certificates must be | |
| 119 // set first. | |
| 120 void NegotiateBeforeQuic(QuicTestPeer* peer, | |
| 121 IceRole ice_role, | |
| 122 rtc::SSLRole local_ssl_role, | |
| 123 rtc::SSLRole remote_ssl_role) { | |
|
pthatcher1
2016/03/01 22:46:52
Should this be called SetIceAndCryptoParameters?
mikescarlett
2016/03/02 02:34:19
I moved the crypto-related stuff outside and put I
| |
| 124 rtc::scoped_refptr<rtc::RTCCertificate> local_cert = | |
| 125 quic_channel()->GetLocalCertificate(); | |
| 126 ASSERT_TRUE(local_cert); | |
| 127 rtc::scoped_refptr<rtc::RTCCertificate> remote_cert = | |
| 128 peer->quic_channel()->GetLocalCertificate(); | |
| 129 ASSERT_TRUE(remote_cert); | |
| 130 // Create fingerprints from certificates. | |
| 131 rtc::scoped_ptr<rtc::SSLFingerprint> local_fingerprint; | |
| 132 rtc::scoped_ptr<rtc::SSLFingerprint> remote_fingerprint; | |
| 133 local_fingerprint.reset(CreateFingerprint(local_cert.get())); | |
| 134 ASSERT_NE(local_fingerprint, nullptr); | |
| 135 remote_fingerprint.reset(CreateFingerprint(remote_cert.get())); | |
| 136 ASSERT_NE(remote_fingerprint, nullptr); | |
| 137 // Pass the ICE credentials to the underlying channel. | |
| 138 SetIceCredentials(ice_role, local_fingerprint.get(), | |
| 139 remote_fingerprint.get(), local_ssl_role, | |
| 140 remote_ssl_role); | |
| 141 // Set SSL and fingerprint parameters for QUIC channel. | |
| 142 quic_channel_.SetSslRole(local_ssl_role); | |
| 143 quic_channel_.SetRemoteFingerprint( | |
| 144 remote_fingerprint->algorithm, | |
| 145 reinterpret_cast<const uint8_t*>(remote_fingerprint->digest.data()), | |
| 146 remote_fingerprint->digest.size()); | |
| 147 } | |
| 148 | |
| 149 // Generates ICE credentials and passes them to |quic_channel_|. | |
| 150 void SetIceCredentials(IceRole ice_role, | |
|
pthatcher1
2016/03/01 22:46:52
Since this is only called once, I'd suggest just i
mikescarlett
2016/03/02 02:34:19
I merged them into SetIceParameters.
| |
| 151 rtc::SSLFingerprint* local_fingerprint, | |
| 152 rtc::SSLFingerprint* remote_fingerprint, | |
| 153 rtc::SSLRole local_ssl_role, | |
| 154 rtc::SSLRole remote_ssl_role) { | |
| 155 quic_channel_.SetIceRole(ice_role); | |
| 156 quic_channel_.SetIceTiebreaker( | |
| 157 (ice_role == cricket::ICEROLE_CONTROLLING) ? 1 : 2); | |
| 158 | |
| 159 ConnectionRole local_connection_role = | |
| 160 SslRoleToConnectionRole(local_ssl_role); | |
| 161 ConnectionRole remote_connection_role = | |
| 162 SslRoleToConnectionRole(remote_ssl_role); | |
| 163 | |
| 164 TransportDescription local_desc(std::vector<std::string>(), kIceUfrag, | |
| 165 kIcePwd, cricket::ICEMODE_FULL, | |
| 166 local_connection_role, local_fingerprint); | |
| 167 TransportDescription remote_desc( | |
| 168 std::vector<std::string>(), kIceUfrag, kIcePwd, cricket::ICEMODE_FULL, | |
| 169 remote_connection_role, remote_fingerprint); | |
| 170 | |
| 171 quic_channel_.SetIceCredentials(local_desc.ice_ufrag, local_desc.ice_pwd); | |
| 172 quic_channel_.SetRemoteIceCredentials(remote_desc.ice_ufrag, | |
| 173 remote_desc.ice_pwd); | |
| 174 } | |
| 175 | |
| 176 // Sets certificate for |quic_channel_|. | |
| 177 void SetLocalCertificate() { | |
| 178 quic_channel_.SetLocalCertificate( | |
| 179 rtc::RTCCertificate::Create(rtc::scoped_ptr<rtc::SSLIdentity>( | |
| 180 rtc::SSLIdentity::Generate(name_, rtc::KT_DEFAULT)))); | |
| 181 } | |
| 182 | |
| 183 // Creates fingerprint from certificate. | |
| 184 rtc::SSLFingerprint* CreateFingerprint(rtc::RTCCertificate* cert) { | |
| 185 std::string digest_algorithm; | |
| 186 bool get_digest_algorithm = | |
| 187 cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm); | |
| 188 if (!get_digest_algorithm || digest_algorithm.empty()) { | |
| 189 return nullptr; | |
| 190 } | |
| 191 scoped_ptr<rtc::SSLFingerprint> fingerprint( | |
| 192 rtc::SSLFingerprint::Create(digest_algorithm, cert->identity())); | |
| 193 if (digest_algorithm != rtc::DIGEST_SHA_256) { | |
| 194 return nullptr; | |
| 195 } | |
| 196 return fingerprint.release(); | |
| 197 } | |
| 198 | |
| 199 // Send packets to the other peer via |quic_channel_|. | |
| 200 void SendPackets(size_t count, bool srtp, bool expect_success) { | |
|
pthatcher1
2016/03/01 22:46:52
This method is only called once, so it seems like
mikescarlett
2016/03/02 02:34:19
Done. Split this and moved asserts like you sugges
| |
| 201 char packet[kPacketSize]; | |
| 202 for (size_t sent = 0; sent < count; ++sent) { | |
| 203 // If |srtp| is true, make this packet look like SRTP. | |
| 204 packet[0] = (srtp) ? 0x80 : 0x00; | |
| 205 // Set the bypass flag if we're sending SRTP. | |
| 206 int flags = srtp ? cricket::PF_SRTP_BYPASS : 0; | |
| 207 rtc::PacketOptions packet_options; | |
| 208 int rv = quic_channel_.SendPacket(&packet[0], kPacketSize, packet_options, | |
| 209 flags); | |
| 210 if (rv > 0) { | |
| 211 ASSERT_TRUE(expect_success); | |
| 212 ASSERT_EQ(kPacketSize, static_cast<size_t>(rv)); | |
| 213 bytes_sent_ += rv; | |
| 214 } else { | |
| 215 ASSERT_FALSE(expect_success); | |
| 216 ASSERT_EQ(-1, rv); | |
| 217 } | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 // Sends a non-SRTP packet with the PF_SRTP_BYPASS flag. | |
| 222 int SendInvalidSrtpPacket() { | |
|
pthatcher1
2016/03/01 22:46:52
Ah, well now it looks like you should have three m
mikescarlett
2016/03/02 02:34:19
Done.
| |
| 223 char packet[kPacketSize]; | |
| 224 // Fill the packet with 0 to form an invalid SRTP packet. | |
| 225 memset(packet, 0, kPacketSize); | |
| 226 rtc::PacketOptions packet_options; | |
| 227 return quic_channel_.SendPacket(&packet[0], kPacketSize, packet_options, | |
| 228 cricket::PF_SRTP_BYPASS); | |
| 229 } | |
| 230 | |
| 231 net::WriteResult WriteQuicPacket(std::string packet) { | |
| 232 return quic_channel_.WritePacket(packet.data(), packet.size(), kIpAddress, | |
| 233 kIpEndpoint); | |
| 234 } | |
| 235 | |
| 236 bool handshake_confirmed() const { | |
|
pthatcher1
2016/03/01 22:46:52
Would a more correct name be quic_connected()?
mikescarlett
2016/03/02 02:34:19
That's fine. Done.
| |
| 237 return quic_channel_.quic_state() == cricket::QUIC_TRANSPORT_CONNECTED; | |
| 238 } | |
| 239 | |
| 240 void ClearBytesSent() { bytes_sent_ = 0; } | |
| 241 | |
| 242 void ClearBytesReceived() { bytes_received_ = 0; } | |
| 243 | |
| 244 void SetWriteError(int error) { fake_channel_.SetError(error); } | |
| 245 | |
| 246 size_t bytes_received() const { return bytes_received_; } | |
| 247 | |
| 248 size_t bytes_sent() const { return bytes_sent_; } | |
| 249 | |
| 250 FakeTransportChannel* fake_channel() { return &fake_channel_; } | |
|
pthatcher1
2016/03/01 22:46:52
I would call this ice_channel(), even though it's
mikescarlett
2016/03/02 02:34:19
Done.
| |
| 251 | |
| 252 QuicTransportChannel* quic_channel() { return &quic_channel_; } | |
| 253 | |
| 254 private: | |
| 255 // QUIC channel callback. | |
| 256 void OnTransportChannelReadPacket(TransportChannel* channel, | |
| 257 const char* data, | |
| 258 size_t size, | |
| 259 const rtc::PacketTime& packet_time, | |
| 260 int flags) { | |
| 261 bytes_received_ += size; | |
| 262 // Only SRTP packets should have the bypass flag set. | |
| 263 int expected_flags = IsRtpLeadByte(data[0]) ? cricket::PF_SRTP_BYPASS : 0; | |
| 264 ASSERT_EQ(expected_flags, flags); | |
| 265 } | |
| 266 | |
| 267 std::string name_; // Channel name. | |
| 268 size_t bytes_sent_; // Bytes sent by QUIC channel. | |
| 269 size_t bytes_received_; // Bytes received by fake channel. | |
| 270 FakeTransportChannel fake_channel_; | |
| 271 QuicTransportChannel quic_channel_; | |
| 272 }; | |
| 273 | |
| 274 class QuicTransportChannelTest : public testing::Test { | |
| 275 public: | |
| 276 QuicTransportChannelTest() : peer1_("P1"), peer2_("P2") {} | |
| 277 | |
| 278 // Performs negotiation before QUIC handshake, then connects the fake | |
| 279 // transport channels of each peer. As a side effect, the QUIC channels | |
| 280 // start sending handshake messages. | |
| 281 void Connect(rtc::SSLRole peer1_ssl_role, rtc::SSLRole peer2_ssl_role) { | |
| 282 ASSERT_NE(peer1_ssl_role, peer2_ssl_role); | |
| 283 NegotiateBeforeQuic(peer1_ssl_role, peer2_ssl_role); | |
| 284 peer1_.Connect(&peer2_); | |
| 285 } | |
| 286 | |
| 287 // By default, |peer1_| has client role and |peer2_| has server role in the | |
| 288 // QUIC handshake. | |
| 289 void Connect() { Connect(rtc::SSL_CLIENT, rtc::SSL_SERVER); } | |
| 290 | |
| 291 // Disconnects the fake transport channels. | |
| 292 void Disconnect() { | |
| 293 peer1_.Disconnect(); | |
| 294 peer2_.Disconnect(); | |
| 295 } | |
| 296 | |
| 297 // Sets up ICE parameters and exchanges fingerprints before QUIC handshake. | |
| 298 void NegotiateBeforeQuic(rtc::SSLRole peer1_ssl_role, | |
| 299 rtc::SSLRole peer2_ssl_role) { | |
| 300 peer1_.NegotiateBeforeQuic(&peer2_, cricket::ICEROLE_CONTROLLED, | |
| 301 peer1_ssl_role, peer2_ssl_role); | |
| 302 peer2_.NegotiateBeforeQuic(&peer1_, cricket::ICEROLE_CONTROLLING, | |
| 303 peer2_ssl_role, peer1_ssl_role); | |
| 304 } | |
|
pthatcher1
2016/03/01 22:46:52
You have 4 methods that basically do a given opera
mikescarlett
2016/03/02 02:34:19
I merged this into one method and will revisit whe
| |
| 305 | |
| 306 // Check whether |peer2_| receives packets sent by |peer1_|. | |
| 307 void TestTransfer(size_t count, bool srtp, bool expect_success) { | |
|
pthatcher1
2016/03/01 22:46:52
I'd suggest to just inline this code into the test
mikescarlett
2016/03/02 02:34:19
Inlined.
| |
| 308 peer1_.ClearBytesSent(); | |
| 309 peer2_.ClearBytesReceived(); | |
| 310 peer1_.SendPackets(count, srtp, expect_success); | |
| 311 | |
| 312 if (expect_success) { | |
| 313 size_t total_bytes = kPacketSize * count; | |
| 314 EXPECT_EQ_WAIT(total_bytes, peer2_.bytes_received(), kTimeoutMs); | |
| 315 EXPECT_EQ(total_bytes, peer1_.bytes_sent()); | |
| 316 } else { | |
| 317 EXPECT_EQ(0u, peer1_.bytes_sent()); | |
| 318 } | |
| 319 } | |
| 320 | |
| 321 // Check that non-SRTP is not sent with the SRTP_BYPASS flag. | |
| 322 void TestTransferInvalidSrtp() { | |
| 323 peer1_.ClearBytesSent(); | |
| 324 peer2_.ClearBytesReceived(); | |
| 325 EXPECT_EQ(-1, peer1_.SendInvalidSrtpPacket()); | |
| 326 EXPECT_EQ(0u, peer2_.bytes_received()); | |
| 327 } | |
| 328 | |
| 329 // Check that peers export identical keying material after the QUIC handshake. | |
| 330 void TestExportKeyingMaterial() { | |
|
pthatcher1
2016/03/01 22:46:52
Same here: Just put this in the test case.
mikescarlett
2016/03/02 02:34:19
Inlined.
| |
| 331 uint8_t key1[kOutputKeyLength]; | |
| 332 uint8_t key2[kOutputKeyLength]; | |
| 333 | |
| 334 bool from_success = peer1_.quic_channel()->ExportKeyingMaterial( | |
| 335 kExporterLabel, kExporterContext, kExporterContextLength, true, key1, | |
| 336 kOutputKeyLength); | |
| 337 ASSERT_TRUE(from_success); | |
| 338 bool to_success = peer2_.quic_channel()->ExportKeyingMaterial( | |
| 339 kExporterLabel, kExporterContext, kExporterContextLength, true, key2, | |
| 340 kOutputKeyLength); | |
| 341 ASSERT_TRUE(to_success); | |
| 342 | |
| 343 EXPECT_EQ(0, memcmp(key1, key2, sizeof(key1))); | |
| 344 } | |
| 345 | |
| 346 // Checks if QUIC handshake is done. | |
| 347 bool handshake_confirmed() const { | |
| 348 return peer1_.handshake_confirmed() && peer2_.handshake_confirmed(); | |
| 349 } | |
| 350 | |
| 351 // Checks if QUIC channels are writable. | |
| 352 bool quic_writable() { | |
| 353 return peer1_.quic_channel()->writable() && | |
| 354 peer2_.quic_channel()->writable(); | |
| 355 } | |
| 356 | |
| 357 protected: | |
| 358 // QUIC peer with a client role, who initiates the QUIC handshake. | |
| 359 QuicTestPeer peer1_; | |
| 360 // QUIC peer with a server role, who responds to the client peer. | |
| 361 QuicTestPeer peer2_; | |
| 362 }; | |
| 363 | |
| 364 // Test that the QUIC channel passes down ICE parameters to the underlying ICE | |
| 365 // channel. | |
| 366 TEST_F(QuicTransportChannelTest, ChannelSetupIce) { | |
| 367 NegotiateBeforeQuic(rtc::SSL_CLIENT, rtc::SSL_SERVER); | |
| 368 FakeTransportChannel* channel1 = peer1_.fake_channel(); | |
| 369 FakeTransportChannel* channel2 = peer2_.fake_channel(); | |
| 370 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel1->GetIceRole()); | |
| 371 EXPECT_EQ(2u, channel1->IceTiebreaker()); | |
| 372 EXPECT_EQ(kIceUfrag, channel1->ice_ufrag()); | |
| 373 EXPECT_EQ(kIcePwd, channel1->ice_pwd()); | |
| 374 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel2->GetIceRole()); | |
| 375 EXPECT_EQ(1u, channel2->IceTiebreaker()); | |
| 376 } | |
| 377 | |
| 378 // Test export keying material after QUIC handshake. | |
| 379 TEST_F(QuicTransportChannelTest, ExportKeyingMaterial) { | |
| 380 Connect(); | |
| 381 ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs); | |
| 382 TestExportKeyingMaterial(); | |
| 383 } | |
| 384 | |
| 385 // Test that QUIC channel is not writable before the QUIC handshake. | |
| 386 TEST_F(QuicTransportChannelTest, NotWritableBeforeHandshake) { | |
| 387 Connect(); | |
| 388 EXPECT_FALSE(quic_writable()); | |
| 389 Disconnect(); | |
| 390 EXPECT_FALSE(quic_writable()); | |
| 391 Connect(); | |
| 392 EXPECT_FALSE(quic_writable()); | |
| 393 } | |
| 394 | |
| 395 // Test that once handshake begins, QUIC is not writable until its completion. | |
| 396 TEST_F(QuicTransportChannelTest, QuicHandshake) { | |
| 397 Connect(); | |
| 398 EXPECT_FALSE(quic_writable()); | |
| 399 ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs); | |
| 400 EXPECT_TRUE(quic_writable()); | |
| 401 } | |
| 402 | |
| 403 // Non-SRTP data should not be sent using SendPacket(), regardless of QUIC | |
| 404 // channel state. | |
| 405 TEST_F(QuicTransportChannelTest, TransferNonSrtp) { | |
| 406 TestTransfer(1, false, false); | |
| 407 TestTransfer(1, true, false); | |
| 408 Connect(); | |
| 409 TestTransfer(1, false, false); | |
| 410 ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs); | |
| 411 TestTransfer(1, false, false); | |
| 412 } | |
| 413 | |
| 414 // SRTP data should always be sent, regardless of QUIC channel state. | |
| 415 TEST_F(QuicTransportChannelTest, TransferSrtp) { | |
| 416 Connect(); | |
| 417 TestTransfer(10, true, true); | |
| 418 ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs); | |
| 419 TestTransfer(10, true, true); | |
| 420 } | |
| 421 | |
| 422 // Test that invalid SRTP (non-SRTP data with | |
| 423 // PF_SRTP_BYPASS flag) fails to send with return value -1. | |
| 424 TEST_F(QuicTransportChannelTest, TransferInvalidSrtp) { | |
| 425 TestTransferInvalidSrtp(); | |
| 426 Connect(); | |
| 427 TestTransferInvalidSrtp(); | |
| 428 } | |
| 429 | |
| 430 // Test that QuicTransportChannel::WritePacket blocks when underlying channel | |
|
pthatcher1
2016/03/01 22:46:52
when underlying => when the underlying
mikescarlett
2016/03/02 02:34:19
Done.
| |
| 431 // is not writable, and otherwise succeeds. | |
| 432 TEST_F(QuicTransportChannelTest, QuicWritePacket) { | |
| 433 peer1_.fake_channel()->Connect(); | |
| 434 peer2_.fake_channel()->Connect(); | |
| 435 peer1_.fake_channel()->SetDestination(peer2_.fake_channel()); | |
| 436 std::string packet = "FAKEQUICPACKET"; | |
| 437 | |
| 438 // QUIC should be write blocked when the underlying channel is not writable. | |
| 439 peer1_.fake_channel()->SetWritable(false); | |
| 440 EXPECT_TRUE(peer1_.quic_channel()->IsWriteBlocked()); | |
| 441 net::WriteResult write_blocked_result = peer1_.WriteQuicPacket(packet); | |
| 442 EXPECT_EQ(net::WRITE_STATUS_BLOCKED, write_blocked_result.status); | |
| 443 EXPECT_EQ(EWOULDBLOCK, write_blocked_result.error_code); | |
| 444 | |
| 445 // QUIC should ignore errors when the underlying channel is writable. | |
| 446 peer1_.fake_channel()->SetWritable(true); | |
| 447 EXPECT_FALSE(peer1_.quic_channel()->IsWriteBlocked()); | |
| 448 peer1_.SetWriteError(EWOULDBLOCK); | |
| 449 net::WriteResult ignore_error_result = peer1_.WriteQuicPacket(packet); | |
| 450 EXPECT_EQ(net::WRITE_STATUS_OK, ignore_error_result.status); | |
| 451 EXPECT_EQ(0, ignore_error_result.bytes_written); | |
| 452 | |
| 453 peer1_.SetWriteError(kNoWriteError); | |
| 454 net::WriteResult no_error_result = peer1_.WriteQuicPacket(packet); | |
| 455 EXPECT_EQ(net::WRITE_STATUS_OK, no_error_result.status); | |
| 456 EXPECT_EQ(static_cast<int>(packet.size()), no_error_result.bytes_written); | |
| 457 } | |
| 458 | |
| 459 // Test that SSL roles can be reversed before QUIC handshake. | |
| 460 TEST_F(QuicTransportChannelTest, QuicRoleReversalBeforeQuic) { | |
| 461 EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); | |
| 462 EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_CLIENT)); | |
| 463 EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); | |
| 464 } | |
| 465 | |
| 466 // Test that SSL roles cannot be reversed after QUIC handshake. SetSslRole | |
| 467 // returns true if the current SSL role equals the proposed SSL role. | |
| 468 TEST_F(QuicTransportChannelTest, QuicRoleReversalAfterQuic) { | |
| 469 Connect(); | |
| 470 ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs); | |
| 471 EXPECT_FALSE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); | |
| 472 EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_CLIENT)); | |
| 473 EXPECT_FALSE(peer2_.quic_channel()->SetSslRole(rtc::SSL_CLIENT)); | |
| 474 EXPECT_TRUE(peer2_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); | |
| 475 } | |
| 476 | |
| 477 // Set SSL role, then check that GetSslRole returns the same value. | |
| 478 TEST_F(QuicTransportChannelTest, SetGetSslRole) { | |
| 479 ASSERT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER)); | |
| 480 rtc::scoped_ptr<rtc::SSLRole> role(new rtc::SSLRole()); | |
| 481 ASSERT_TRUE(peer1_.quic_channel()->GetSslRole(role.get())); | |
| 482 EXPECT_EQ(rtc::SSL_SERVER, *role); | |
| 483 } | |
| 484 | |
| 485 // Test that after QUIC handshake is complete, QUIC handshake remains confirmed | |
| 486 // even if underlying channel reconnects. | |
| 487 TEST_F(QuicTransportChannelTest, HandshakeConfirmedAfterReconnect) { | |
| 488 Connect(); | |
| 489 ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs); | |
| 490 Disconnect(); | |
| 491 EXPECT_TRUE(handshake_confirmed()); | |
| 492 Connect(); | |
| 493 EXPECT_TRUE(handshake_confirmed()); | |
| 494 } | |
| OLD | NEW |