| Index: webrtc/p2p/quic/quictransportchannel_unittest.cc
|
| diff --git a/webrtc/p2p/quic/quictransportchannel_unittest.cc b/webrtc/p2p/quic/quictransportchannel_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..77cf1d9b800b3e284b236ca2c7d83023c4bc86f5
|
| --- /dev/null
|
| +++ b/webrtc/p2p/quic/quictransportchannel_unittest.cc
|
| @@ -0,0 +1,535 @@
|
| +/*
|
| + * Copyright 2016 The WebRTC Project Authors. All rights reserved.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license
|
| + * that can be found in the LICENSE file in the root of the source
|
| + * tree. An additional intellectual property rights grant can be found
|
| + * in the file PATENTS. All contributing project authors may
|
| + * be found in the AUTHORS file in the root of the source tree.
|
| + */
|
| +
|
| +#include "webrtc/p2p/quic/quictransportchannel.h"
|
| +
|
| +#include <set>
|
| +#include <string>
|
| +#include <vector>
|
| +
|
| +#include "webrtc/base/common.h"
|
| +#include "webrtc/base/gunit.h"
|
| +#include "webrtc/base/scoped_ptr.h"
|
| +#include "webrtc/base/sslidentity.h"
|
| +#include "webrtc/p2p/base/faketransportcontroller.h"
|
| +
|
| +using cricket::ConnectionRole;
|
| +using cricket::IceRole;
|
| +using cricket::QuicTransportChannel;
|
| +using cricket::TransportChannel;
|
| +using cricket::TransportDescription;
|
| +
|
| +// Timeout in milliseconds for asynchronous operations in unit tests.
|
| +const int kTimeoutMs = 1000;
|
| +
|
| +// Export keying material parameters.
|
| +const char kExporterLabel[] = "label";
|
| +const uint8_t kExporterContext[] = "context";
|
| +const size_t kExporterContextLength = sizeof(kExporterContext);
|
| +const size_t kOutputKeyLength = 20;
|
| +
|
| +// Indicates channel has no write error.
|
| +const int kNoWriteError = 0;
|
| +
|
| +// ICE parameters.
|
| +const char kIceUfrag[] = "TESTICEUFRAG0001";
|
| +const char kIcePwd[] = "TESTICEPWD00000000000001";
|
| +
|
| +// QUIC packet parameters.
|
| +const net::IPAddressNumber kIpAddress(net::kIPv4AddressSize, 0);
|
| +const net::IPEndPoint kIpEndpoint(kIpAddress, 0);
|
| +
|
| +// Packet number offset for making test packets.
|
| +const size_t kPacketNumOffset = 8;
|
| +
|
| +// Detects incoming RTP packets.
|
| +bool IsRtpLeadByte(uint8_t b) {
|
| + return (b & 0xC0) == 0x80;
|
| +}
|
| +// Detects incoming QUIC packets.
|
| +bool IsQuicLeadByte(uint8_t b) {
|
| + return (b & 0x80) == 0;
|
| +}
|
| +
|
| +// Maps SSL role to ICE connection role. The peer with a client role is assumed
|
| +// to be the one who initiates the connection.
|
| +ConnectionRole SslRoleToConnectionRole(rtc::SSLRole ssl_role) {
|
| + return (ssl_role == rtc::SSL_CLIENT) ? cricket::CONNECTIONROLE_ACTIVE
|
| + : cricket::CONNECTIONROLE_PASSIVE;
|
| +}
|
| +
|
| +// Allows cricket::FakeTransportChannel to simulate write blocked
|
| +// and write error states.
|
| +// TODO(mikescarlett): Consider adding this functionality to
|
| +// cricket::FakeTransportChannel.
|
| +class FakeTransportChannel : public cricket::FakeTransportChannel {
|
| + public:
|
| + FakeTransportChannel(const std::string& name, int component)
|
| + : cricket::FakeTransportChannel(name, component), error_(kNoWriteError) {}
|
| + int GetError() override { return error_; }
|
| + void SetError(int error) { error_ = error; }
|
| + int SendPacket(const char* data,
|
| + size_t len,
|
| + const rtc::PacketOptions& options,
|
| + int flags) override {
|
| + if (error_ == kNoWriteError) {
|
| + return cricket::FakeTransportChannel::SendPacket(data, len, options,
|
| + flags);
|
| + }
|
| + return -1;
|
| + }
|
| +
|
| + private:
|
| + int error_;
|
| +};
|
| +
|
| +// Peer who establishes a handshake using a QuicTransportChannel, which wraps
|
| +// a FakeTransportChannel to simulate network connectivity and ICE negotiation.
|
| +class QuicTestPeer : public sigslot::has_slots<> {
|
| + public:
|
| + explicit QuicTestPeer(const std::string& name)
|
| + : name_(name),
|
| + bytes_sent_(0),
|
| + fake_channel_(name_, 0),
|
| + quic_channel_(&fake_channel_) {
|
| + quic_channel_.SignalReadPacket.connect(
|
| + this, &QuicTestPeer::OnTransportChannelReadPacket);
|
| + fake_channel_.SetAsync(true);
|
| + }
|
| +
|
| + // Connects |fake_channel_| to that of the other peer.
|
| + void Connect(QuicTestPeer* peer) {
|
| + fake_channel_.Connect();
|
| + peer->fake_channel_.Connect();
|
| + fake_channel_.SetDestination(&peer->fake_channel_);
|
| + }
|
| +
|
| + // Disconnects |fake_channel_|.
|
| + void Disconnect() { fake_channel_.SetDestination(nullptr); }
|
| +
|
| + // Simulates the fingerprint exchange and ICE parameter negotiation
|
| + // which is done before QUIC handshake is started.
|
| + void NegotiateBeforeQuic(QuicTestPeer* peer,
|
| + IceRole ice_role,
|
| + rtc::SSLRole local_ssl_role,
|
| + rtc::SSLRole remote_ssl_role) {
|
| + rtc::scoped_refptr<rtc::RTCCertificate> local_cert =
|
| + quic_channel()->GetLocalCertificate();
|
| + rtc::scoped_refptr<rtc::RTCCertificate> remote_cert =
|
| + local_cert ? peer->quic_channel()->GetLocalCertificate() : nullptr;
|
| + rtc::scoped_ptr<rtc::SSLFingerprint> local_fingerprint;
|
| + rtc::scoped_ptr<rtc::SSLFingerprint> remote_fingerprint;
|
| + if (local_cert) {
|
| + local_fingerprint.reset(CreateFingerprint(local_cert.get()));
|
| + ASSERT_NE(local_fingerprint, nullptr);
|
| + }
|
| + if (remote_cert) {
|
| + remote_fingerprint.reset(CreateFingerprint(remote_cert.get()));
|
| + ASSERT_NE(remote_fingerprint, nullptr);
|
| + }
|
| + SetIceCredentials(ice_role, local_fingerprint.get(),
|
| + remote_fingerprint.get(), local_ssl_role,
|
| + remote_ssl_role);
|
| + quic_channel_.SetSslRole(local_ssl_role);
|
| + if (remote_fingerprint) {
|
| + quic_channel_.SetRemoteFingerprint(
|
| + remote_fingerprint->algorithm,
|
| + reinterpret_cast<const uint8_t*>(remote_fingerprint->digest.data()),
|
| + remote_fingerprint->digest.size());
|
| + }
|
| + }
|
| +
|
| + // Generates ICE credentials and passes them to |quic_channel_|.
|
| + void SetIceCredentials(IceRole ice_role,
|
| + rtc::SSLFingerprint* local_fingerprint,
|
| + rtc::SSLFingerprint* remote_fingerprint,
|
| + rtc::SSLRole local_ssl_role,
|
| + rtc::SSLRole remote_ssl_role) {
|
| + quic_channel_.SetIceRole(ice_role);
|
| + quic_channel_.SetIceTiebreaker(
|
| + (ice_role == cricket::ICEROLE_CONTROLLING) ? 1 : 2);
|
| +
|
| + ConnectionRole local_connection_role =
|
| + SslRoleToConnectionRole(local_ssl_role);
|
| + ConnectionRole remote_connection_role =
|
| + SslRoleToConnectionRole(remote_ssl_role);
|
| +
|
| + TransportDescription local_desc(std::vector<std::string>(), kIceUfrag,
|
| + kIcePwd, cricket::ICEMODE_FULL,
|
| + local_connection_role, local_fingerprint);
|
| + TransportDescription remote_desc(
|
| + std::vector<std::string>(), kIceUfrag, kIcePwd, cricket::ICEMODE_FULL,
|
| + remote_connection_role, remote_fingerprint);
|
| +
|
| + quic_channel_.SetIceCredentials(local_desc.ice_ufrag, local_desc.ice_pwd);
|
| + quic_channel_.SetRemoteIceCredentials(remote_desc.ice_ufrag,
|
| + remote_desc.ice_pwd);
|
| + }
|
| +
|
| + // Sets certificate for |quic_channel_|.
|
| + void SetLocalCertificate(rtc::KeyType key_type) {
|
| + quic_channel_.SetLocalCertificate(
|
| + rtc::RTCCertificate::Create(rtc::scoped_ptr<rtc::SSLIdentity>(
|
| + rtc::SSLIdentity::Generate(name_, key_type))));
|
| + }
|
| +
|
| + // Creates fingerprint from certificate.
|
| + rtc::SSLFingerprint* CreateFingerprint(rtc::RTCCertificate* cert) {
|
| + std::string digest_algorithm;
|
| + bool get_digest_algorithm =
|
| + cert->ssl_certificate().GetSignatureDigestAlgorithm(&digest_algorithm);
|
| + if (!get_digest_algorithm || digest_algorithm.empty()) {
|
| + return nullptr;
|
| + }
|
| + scoped_ptr<rtc::SSLFingerprint> fingerprint(
|
| + rtc::SSLFingerprint::Create(digest_algorithm, cert->identity()));
|
| + if (digest_algorithm != rtc::DIGEST_SHA_256) {
|
| + return nullptr;
|
| + }
|
| + return fingerprint.release();
|
| + }
|
| +
|
| + // Send packets to the other peer via |quic_channel_|.
|
| + void SendPackets(const size_t kSize,
|
| + size_t count,
|
| + bool srtp,
|
| + bool expect_success) {
|
| + ASSERT_GT(kSize, kPacketNumOffset);
|
| + char packet[kSize];
|
| + for (size_t sent = 0; sent < count; ++sent) {
|
| + // Fill the packet with a known value and a sequence number to check
|
| + // against, and make sure that it doesn't look like QUIC.
|
| + memset(&packet, sent & 0xff, kSize);
|
| + packet[0] = (srtp) ? 0x80 : 0x00;
|
| + rtc::SetBE32(&packet + kPacketNumOffset, static_cast<uint32_t>(sent));
|
| + // Only set the bypass flag if we've activated QUIC.
|
| + int flags = srtp ? cricket::PF_SRTP_BYPASS : 0;
|
| + rtc::PacketOptions packet_options;
|
| + int rv =
|
| + quic_channel_.SendPacket(&packet[0], kSize, packet_options, flags);
|
| + if (rv > 0) {
|
| + ASSERT_TRUE(expect_success);
|
| + ASSERT_EQ(kSize, static_cast<size_t>(rv));
|
| + bytes_sent_ += rv;
|
| + } else {
|
| + ASSERT_FALSE(expect_success);
|
| + ASSERT_EQ(-1, rv);
|
| + }
|
| + }
|
| + }
|
| +
|
| + // Sends a non-SRTP packet with the PF_SRTP_BYPASS flag.
|
| + int SendInvalidSrtpPacket(size_t channel, size_t size) {
|
| + rtc::scoped_ptr<char[]> packet(new char[size]);
|
| + // Fill the packet with 0 to form an invalid SRTP packet.
|
| + memset(packet.get(), 0, size);
|
| +
|
| + rtc::PacketOptions packet_options;
|
| + return quic_channel_.SendPacket(packet.get(), size, packet_options,
|
| + cricket::PF_SRTP_BYPASS);
|
| + }
|
| +
|
| + net::WriteResult WriteQuicPacket(std::string packet) {
|
| + return quic_channel_.WritePacket(packet.data(), packet.size(), kIpAddress,
|
| + kIpEndpoint);
|
| + }
|
| +
|
| + bool handshake_confirmed() const {
|
| + return quic_channel_.quic_state() == cricket::QUIC_TRANSPORT_CONNECTED;
|
| + }
|
| +
|
| + void ClearPackets() { received_.clear(); }
|
| +
|
| + void SetWriteError(int error) { fake_channel_.SetError(error); }
|
| +
|
| + size_t num_packets_received() const { return received_.size(); }
|
| +
|
| + size_t bytes_sent() const { return bytes_sent_; }
|
| +
|
| + FakeTransportChannel* fake_channel() { return &fake_channel_; }
|
| +
|
| + QuicTransportChannel* quic_channel() { return &quic_channel_; }
|
| +
|
| + private:
|
| + // QUIC channel callback.
|
| + void OnTransportChannelReadPacket(TransportChannel* channel,
|
| + const char* data,
|
| + size_t size,
|
| + const rtc::PacketTime& packet_time,
|
| + int flags) {
|
| + uint32_t packet_num = rtc::GetBE32(data + kPacketNumOffset);
|
| + // Check that packet number was not received yet.
|
| + ASSERT_TRUE(received_.insert(packet_num).second);
|
| + // Only SRTP packets should have the bypass flag set.
|
| + int expected_flags = handshake_confirmed() && IsRtpLeadByte(data[0])
|
| + ? cricket::PF_SRTP_BYPASS
|
| + : 0;
|
| + ASSERT_EQ(expected_flags, flags);
|
| + }
|
| +
|
| + std::string name_; // Channel name.
|
| + std::set<int> received_; // Packet numbers received.
|
| + size_t bytes_sent_; // Bytes sent by QUIC channel.
|
| + FakeTransportChannel fake_channel_;
|
| + QuicTransportChannel quic_channel_;
|
| +};
|
| +
|
| +class QuicTransportChannelTest : public testing::Test {
|
| + public:
|
| + QuicTransportChannelTest() : peer1_("P1"), peer2_("P2") {}
|
| +
|
| + // Sets certificates for QUIC channels.
|
| + void PrepareQuic(bool c1, bool c2, rtc::KeyType key_type) {
|
| + if (c1) {
|
| + peer1_.SetLocalCertificate(key_type);
|
| + }
|
| + if (c2) {
|
| + peer2_.SetLocalCertificate(key_type);
|
| + }
|
| + }
|
| +
|
| + // Performs preconditions of QUIC handshake, then connects the fake transport
|
| + // channels of each peer. As a side effect, the QUIC channels should start
|
| + // sending handshake messages.
|
| + void Connect(rtc::SSLRole peer1_ssl_role, rtc::SSLRole peer2_ssl_role) {
|
| + ASSERT_NE(peer1_ssl_role, peer2_ssl_role);
|
| + NegotiateBeforeQuic(peer1_ssl_role, peer2_ssl_role);
|
| + peer1_.Connect(&peer2_);
|
| + }
|
| +
|
| + // By default, |peer1_| has client role and |peer2_| has server role in the
|
| + // QUIC handshake.
|
| + void Connect() { Connect(rtc::SSL_CLIENT, rtc::SSL_SERVER); }
|
| +
|
| + // Disconnects the fake transport channels.
|
| + void Disconnect() {
|
| + peer1_.Disconnect();
|
| + peer2_.Disconnect();
|
| + }
|
| +
|
| + // Sets up ICE parameters and exchanges fingerprints before QUIC handshake.
|
| + void NegotiateBeforeQuic(rtc::SSLRole peer1_ssl_role,
|
| + rtc::SSLRole peer2_ssl_role) {
|
| + peer1_.NegotiateBeforeQuic(&peer2_, cricket::ICEROLE_CONTROLLED,
|
| + peer1_ssl_role, peer2_ssl_role);
|
| + peer2_.NegotiateBeforeQuic(&peer1_, cricket::ICEROLE_CONTROLLING,
|
| + peer2_ssl_role, peer1_ssl_role);
|
| + }
|
| +
|
| + // Check whether |peer2_| receives packets sent by |peer1_|.
|
| + void TestTransfer(size_t size, size_t count, bool srtp, bool expect_success) {
|
| + LOG(LS_INFO) << "Expect packets, size=" << size << ", srtp=" << srtp
|
| + << ", success=" << expect_success;
|
| + peer2_.ClearPackets();
|
| + peer1_.SendPackets(size, count, srtp, expect_success);
|
| +
|
| + if (expect_success) {
|
| + EXPECT_EQ_WAIT(count, peer2_.num_packets_received(), kTimeoutMs);
|
| + EXPECT_EQ(size * count, peer1_.bytes_sent());
|
| + } else {
|
| + EXPECT_EQ(0u, peer1_.bytes_sent());
|
| + }
|
| + }
|
| +
|
| + // Check that peers export identical keying material after the QUIC handshake.
|
| + void TestExportKeyingMaterial() {
|
| + uint8_t key1[kOutputKeyLength];
|
| + uint8_t key2[kOutputKeyLength];
|
| +
|
| + bool from_success = peer1_.quic_channel()->ExportKeyingMaterial(
|
| + kExporterLabel, kExporterContext, kExporterContextLength, true, key1,
|
| + kOutputKeyLength);
|
| + ASSERT_TRUE(from_success);
|
| + bool to_success = peer2_.quic_channel()->ExportKeyingMaterial(
|
| + kExporterLabel, kExporterContext, kExporterContextLength, true, key2,
|
| + kOutputKeyLength);
|
| + ASSERT_TRUE(to_success);
|
| +
|
| + EXPECT_EQ(0, memcmp(key1, key2, sizeof(key1)));
|
| + }
|
| +
|
| + // Checks if QUIC handshake is done.
|
| + bool handshake_confirmed() const {
|
| + return peer1_.handshake_confirmed() && peer2_.handshake_confirmed();
|
| + }
|
| +
|
| + // Checks if QUIC channels are writable.
|
| + bool quic_writable() {
|
| + return peer1_.quic_channel()->writable() &&
|
| + peer2_.quic_channel()->writable();
|
| + }
|
| +
|
| + protected:
|
| + // QUIC peer with a client role, who initiates the QUIC handshake.
|
| + QuicTestPeer peer1_;
|
| + // QUIC peer with a server role, who responds to the client peer.
|
| + QuicTestPeer peer2_;
|
| +};
|
| +
|
| +// Test that the QUIC channel passes down ICE parameters to the underlying ICE
|
| +// channel.
|
| +TEST_F(QuicTransportChannelTest, ChannelSetupIce) {
|
| + NegotiateBeforeQuic(rtc::SSL_CLIENT, rtc::SSL_SERVER);
|
| + FakeTransportChannel* channel1 = peer1_.fake_channel();
|
| + FakeTransportChannel* channel2 = peer2_.fake_channel();
|
| + EXPECT_EQ(cricket::ICEROLE_CONTROLLED, channel1->GetIceRole());
|
| + EXPECT_EQ(2u, channel1->IceTiebreaker());
|
| + EXPECT_EQ(kIceUfrag, channel1->ice_ufrag());
|
| + EXPECT_EQ(kIcePwd, channel1->ice_pwd());
|
| + EXPECT_EQ(cricket::ICEROLE_CONTROLLING, channel2->GetIceRole());
|
| + EXPECT_EQ(1u, channel2->IceTiebreaker());
|
| +}
|
| +
|
| +// Test export keying material after QUIC handshake.
|
| +TEST_F(QuicTransportChannelTest, ExportKeyingMaterial) {
|
| + PrepareQuic(true, true, rtc::KT_DEFAULT);
|
| + Connect();
|
| + ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs);
|
| + TestExportKeyingMaterial();
|
| +}
|
| +
|
| +// Test that QUIC channel connectivity state is consistent
|
| +// with underlying channel before the QUIC handshake.
|
| +TEST_F(QuicTransportChannelTest, ConnectDisconnect) {
|
| + Connect();
|
| + EXPECT_TRUE(quic_writable());
|
| + Disconnect();
|
| + EXPECT_FALSE(quic_writable());
|
| + Connect();
|
| + EXPECT_TRUE(quic_writable());
|
| + Disconnect();
|
| + EXPECT_FALSE(quic_writable());
|
| +}
|
| +
|
| +// Test that once handshake begins, QUIC is not connected until its completion.
|
| +TEST_F(QuicTransportChannelTest, QuicHandshake) {
|
| + PrepareQuic(true, true, rtc::KT_DEFAULT);
|
| + Connect();
|
| + EXPECT_FALSE(quic_writable());
|
| + ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs);
|
| + EXPECT_TRUE(quic_writable());
|
| +}
|
| +
|
| +// Test that QuicTransportChannel::SendPacket fails before peers are connected.
|
| +TEST_F(QuicTransportChannelTest, TransferBeforeConnect) {
|
| + TestTransfer(100, 1, false, false);
|
| + TestTransfer(100, 1, true, false);
|
| +}
|
| +
|
| +// Connect without QUIC, and transfer non-SRTP data.
|
| +TEST_F(QuicTransportChannelTest, TransferBeforeQuic) {
|
| + Connect();
|
| + TestTransfer(100, 10, false, true);
|
| +}
|
| +
|
| +// Connect without QUIC, and transfer SRTP data.
|
| +TEST_F(QuicTransportChannelTest, TransferSrtpBeforeQuic) {
|
| + Connect();
|
| + TestTransfer(100, 10, true, true);
|
| +}
|
| +
|
| +// Connect with QUIC, and transfer SRTP data.
|
| +TEST_F(QuicTransportChannelTest, TransferSrtpAfterQuic) {
|
| + PrepareQuic(true, true, rtc::KT_DEFAULT);
|
| + Connect();
|
| + ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs);
|
| + TestTransfer(100, 10, true, true);
|
| +}
|
| +
|
| +// Connect with QUIC, and test that invalid SRTP (non-SRTP data with
|
| +// PF_SRTP_BYPASS flag) fails to send with return value -1.
|
| +TEST_F(QuicTransportChannelTest, TransferInvalidSrtpAfterQuic) {
|
| + PrepareQuic(true, true, rtc::KT_DEFAULT);
|
| + Connect();
|
| + int result = peer1_.SendInvalidSrtpPacket(0, 100);
|
| + EXPECT_EQ(-1, result);
|
| + EXPECT_EQ(0u, peer2_.num_packets_received());
|
| +}
|
| +
|
| +// Test QuicTransportChannel::WritePacket return values under various states
|
| +// of the wrapped channel.
|
| +TEST_F(QuicTransportChannelTest, QuicWritePacket) {
|
| + peer1_.fake_channel()->Connect();
|
| + peer2_.fake_channel()->Connect();
|
| + peer1_.fake_channel()->SetDestination(peer2_.fake_channel());
|
| +
|
| + // Write blocked error.
|
| + peer1_.SetWriteError(EWOULDBLOCK);
|
| + std::string packet = "FAKEQUICPACKET";
|
| + net::WriteResult write_blocked_result = peer1_.WriteQuicPacket(packet);
|
| + EXPECT_EQ(net::WRITE_STATUS_BLOCKED, write_blocked_result.status);
|
| + EXPECT_EQ(EWOULDBLOCK, write_blocked_result.error_code);
|
| +
|
| + // Errors other than write blocked.
|
| + peer1_.SetWriteError(ETIMEDOUT);
|
| + net::WriteResult write_error_result = peer1_.WriteQuicPacket(packet);
|
| + EXPECT_EQ(net::WRITE_STATUS_BLOCKED, write_error_result.status);
|
| + EXPECT_EQ(ETIMEDOUT, write_error_result.error_code);
|
| +
|
| + // No error.
|
| + peer1_.SetWriteError(kNoWriteError);
|
| + net::WriteResult no_error_result = peer1_.WriteQuicPacket(packet);
|
| + EXPECT_EQ(net::WRITE_STATUS_OK, no_error_result.status);
|
| + EXPECT_EQ(static_cast<int>(packet.size()), no_error_result.bytes_written);
|
| +}
|
| +
|
| +// Test that SSL roles can be reversed before QUIC handshake.
|
| +TEST_F(QuicTransportChannelTest, QuicRoleReversalBeforeQuic) {
|
| + EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER));
|
| + EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_CLIENT));
|
| + EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER));
|
| +}
|
| +
|
| +// Test that SSL roles cannot be reversed after QUIC handshake. SetSslRole
|
| +// returns true if the current SSL role equals the proposed SSL role.
|
| +TEST_F(QuicTransportChannelTest, QuicRoleReversalAfterQuic) {
|
| + PrepareQuic(true, true, rtc::KT_DEFAULT);
|
| + Connect();
|
| + ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs);
|
| + EXPECT_FALSE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER));
|
| + EXPECT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_CLIENT));
|
| + EXPECT_FALSE(peer2_.quic_channel()->SetSslRole(rtc::SSL_CLIENT));
|
| + EXPECT_TRUE(peer2_.quic_channel()->SetSslRole(rtc::SSL_SERVER));
|
| +}
|
| +
|
| +// Set SSL role, then check that GetSslRole returns the same value.
|
| +TEST_F(QuicTransportChannelTest, SetGetSslRole) {
|
| + ASSERT_TRUE(peer1_.quic_channel()->SetSslRole(rtc::SSL_SERVER));
|
| + rtc::scoped_ptr<rtc::SSLRole> role(new rtc::SSLRole());
|
| + ASSERT_TRUE(peer1_.quic_channel()->GetSslRole(role.get()));
|
| + EXPECT_EQ(rtc::SSL_SERVER, *role);
|
| +}
|
| +
|
| +// Test that after QUIC handshake is complete, QUIC handshake remains confirmed
|
| +// even if underlying channel reconnects.
|
| +TEST_F(QuicTransportChannelTest, HandshakeConfirmedAfterReconnect) {
|
| + PrepareQuic(true, true, rtc::KT_DEFAULT);
|
| + Connect();
|
| + ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs);
|
| + Disconnect();
|
| + EXPECT_TRUE(handshake_confirmed());
|
| + Connect();
|
| + EXPECT_TRUE(handshake_confirmed());
|
| +}
|
| +
|
| +// Test that QUIC is able to resume a handshake if the channel becomes write
|
| +// blocked then writable again.
|
| +TEST_F(QuicTransportChannelTest, TestQuicCryptoStreamWriteBlocked) {
|
| + PrepareQuic(true, true, rtc::KT_DEFAULT);
|
| + peer1_.SetWriteError(EWOULDBLOCK);
|
| + ASSERT_FALSE(peer1_.quic_channel()->HasDataToWrite());
|
| + Connect();
|
| + ASSERT_TRUE(peer1_.quic_channel()->HasDataToWrite());
|
| + ASSERT_FALSE(handshake_confirmed());
|
| + peer1_.SetWriteError(kNoWriteError);
|
| + peer1_.quic_channel()->OnCanWrite();
|
| + ASSERT_FALSE(peer1_.quic_channel()->HasDataToWrite());
|
| + ASSERT_TRUE_WAIT(handshake_confirmed(), kTimeoutMs);
|
| +}
|
|
|