Chromium Code Reviews| Index: webrtc/pc/channel_unittest.cc |
| diff --git a/webrtc/pc/channel_unittest.cc b/webrtc/pc/channel_unittest.cc |
| index 99cca88637a877f018c6f7be8c22ee09a42c8023..dd4ec6f995b56cb25dabb366224af19c99d31566 100644 |
| --- a/webrtc/pc/channel_unittest.cc |
| +++ b/webrtc/pc/channel_unittest.cc |
| @@ -101,6 +101,7 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { |
| // Use BaseChannel with PacketTransportInternal rather than |
| // DtlsTransportInternal. |
| RAW_PACKET_TRANSPORT = 0x40, |
| + ENCRYPTED_HEADERS = 0x80, |
| }; |
| ChannelTest(bool verify_playout, |
| @@ -265,6 +266,8 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { |
| (flags & SECURE) != 0); |
| rtc::CryptoOptions crypto_options; |
| crypto_options.enable_gcm_crypto_suites = (flags & GCM_CIPHER) != 0; |
| + crypto_options.enable_encrypted_rtp_header_extensions = |
| + (flags & ENCRYPTED_HEADERS) != 0; |
| channel->SetCryptoOptions(crypto_options); |
| if (!channel->NeedsRtcpTransport()) { |
| fake_rtcp_dtls_transport = nullptr; |
| @@ -892,6 +895,188 @@ class ChannelTest : public testing::Test, public sigslot::has_slots<> { |
| EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0)); |
| } |
| + // Test that encrypted header extensions are working and can be changed when |
| + // sending a new OFFER/ANSWER. |
| + void TestChangeEncryptedHeaderExtensions(int flags, bool asymmetric = false) { |
| + RTC_CHECK(!asymmetric || (flags & DTLS)); |
| + struct PacketListener : public sigslot::has_slots<> { |
| + PacketListener() {} |
| + void OnReadPacket(rtc::PacketTransportInternal* transport, |
| + const char* data, size_t size, const rtc::PacketTime& time, |
| + int flags) { |
| + CompareHeaderExtensions( |
| + reinterpret_cast<const char*>(kPcmuFrameWithExtensions), data, |
| + encrypted_headers, false); |
| + } |
| + std::vector<int> encrypted_headers; |
| + } packet_listener1, packet_listener2; |
| + |
| + cricket::StreamParams stream1; |
| + stream1.groupid = "group1"; |
| + stream1.id = "stream1"; |
| + stream1.ssrcs.push_back(kSsrc1); |
| + stream1.cname = "stream1_cname"; |
| + |
| + cricket::StreamParams stream2; |
| + stream2.groupid = "group1"; |
| + stream2.id = "stream2"; |
| + stream2.ssrcs.push_back(kSsrc2); |
| + stream2.cname = "stream2_cname"; |
| + |
| + // Use SRTP when testing encrypted extensions. |
| + int channel_flags = flags | SECURE | ENCRYPTED_HEADERS; |
| + // Enable SDES if channel is not using DTLS. |
| + int content_flags = (channel_flags & DTLS) == 0 ? SECURE : 0; |
| + |
| + // kPcmuFrameWithExtensions contains RTP extension headers with ids 1-4. |
| + // Make sure to use URIs that are supported for encryption. |
| + cricket::RtpHeaderExtensions extensions1; |
| + extensions1.push_back( |
| + RtpExtension(RtpExtension::kAudioLevelUri, 10)); |
| + extensions1.push_back( |
| + RtpExtension(RtpExtension::kAudioLevelUri, 1, true)); |
| + |
| + cricket::RtpHeaderExtensions extensions2; |
| + extensions2.push_back( |
| + RtpExtension(RtpExtension::kAudioLevelUri, 10)); |
| + extensions2.push_back( |
| + RtpExtension(RtpExtension::kAudioLevelUri, 2, true)); |
| + extensions2.push_back( |
| + RtpExtension(RtpExtension::kVideoRotationUri, 3)); |
| + extensions2.push_back( |
| + RtpExtension(RtpExtension::kTimestampOffsetUri, 4, true)); |
| + |
| + // Setup a call where channel 1 send |stream1| to channel 2. |
| + CreateChannels(channel_flags, channel_flags); |
| + fake_rtp_dtls_transport1_->fake_ice_transport()->SignalReadPacket.connect( |
| + &packet_listener1, &PacketListener::OnReadPacket); |
| + fake_rtp_dtls_transport2_->fake_ice_transport()->SignalReadPacket.connect( |
| + &packet_listener2, &PacketListener::OnReadPacket); |
| + |
| + typename T::Content content1; |
| + CreateContent(content_flags, kPcmuCodec, kH264Codec, &content1); |
| + content1.AddStream(stream1); |
| + content1.set_rtp_header_extensions(extensions1); |
| + EXPECT_TRUE(channel1_->SetLocalContent(&content1, CA_OFFER, NULL)); |
| + EXPECT_TRUE(channel1_->Enable(true)); |
| + EXPECT_EQ(1u, media_channel1_->send_streams().size()); |
| + |
| + EXPECT_TRUE(channel2_->SetRemoteContent(&content1, CA_OFFER, NULL)); |
| + EXPECT_EQ(1u, media_channel2_->recv_streams().size()); |
| + |
| + // Channel 2 sends back |stream2|. |
| + typename T::Content content2; |
| + CreateContent(content_flags, kPcmuCodec, kH264Codec, &content2); |
| + content2.AddStream(stream2); |
| + content2.set_rtp_header_extensions(extensions1); |
| + EXPECT_TRUE(channel1_->SetRemoteContent(&content2, CA_ANSWER, NULL)); |
| + EXPECT_EQ(1u, media_channel1_->recv_streams().size()); |
| + EXPECT_TRUE(channel2_->SetLocalContent(&content2, CA_ANSWER, NULL)); |
| + EXPECT_TRUE(channel2_->Enable(true)); |
| + EXPECT_EQ(1u, media_channel2_->send_streams().size()); |
| + |
| + packet_listener2.encrypted_headers.push_back(1); |
| + |
| + if (asymmetric) { |
| + network_thread_->Invoke<void>(RTC_FROM_HERE, [this, asymmetric] { |
| + if (fake_rtp_dtls_transport1_ && fake_rtp_dtls_transport2_) { |
| + fake_rtp_dtls_transport1_->SetDestination( |
| + fake_rtp_dtls_transport2_.get(), asymmetric); |
| + } |
| + if (fake_rtcp_dtls_transport1_ && fake_rtcp_dtls_transport2_) { |
| + fake_rtcp_dtls_transport1_->SetDestination( |
| + fake_rtcp_dtls_transport2_.get(), asymmetric); |
| + } |
| + }); |
| + // Wait for transports to finish connecting. |
| + WaitForThreads(); |
| + |
| + SendCustomRtp1(kSsrc1, 0); |
| + WaitForThreads(); |
| + |
| + // The packet was dropped by channel 2 because DTLS was not |
| + // negotiated on th receiving side yet. |
| + EXPECT_TRUE(media_channel2_->CheckNoRtp()); |
| + } |
| + |
| + packet_listener1.encrypted_headers.push_back(1); |
| + |
| + if (asymmetric) { |
| + network_thread_->Invoke<void>(RTC_FROM_HERE, [this, asymmetric] { |
| + if (fake_rtp_dtls_transport1_ && fake_rtp_dtls_transport2_) { |
| + fake_rtp_dtls_transport2_->SetDestination( |
| + fake_rtp_dtls_transport1_.get(), asymmetric); |
| + } |
| + if (fake_rtcp_dtls_transport1_ && fake_rtcp_dtls_transport2_) { |
| + fake_rtcp_dtls_transport2_->SetDestination( |
| + fake_rtcp_dtls_transport1_.get(), asymmetric); |
| + } |
| + }); |
| + } else { |
| + ConnectFakeTransports(); |
| + } |
| + // Wait for transports to finish connecting. |
| + WaitForThreads(); |
|
Taylor Brandstetter
2017/04/20 06:37:28
I don't understand how the additions above are rel
joachim
2017/04/24 22:07:48
You mean the code path where "asymmetric" is true?
Taylor Brandstetter
2017/04/24 23:08:17
Sorry if I was unclear. My earlier comment was mor
|
| + |
| + SendCustomRtp1(kSsrc1, 0); |
| + SendCustomRtp2(kSsrc2, 0); |
| + WaitForThreads(); |
| + EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0)); |
| + EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0)); |
| + |
| + // Let channel 2 update the encrypted header extensions. |
| + typename T::Content content3; |
| + CreateContent(content_flags, kPcmuCodec, kH264Codec, &content3); |
| + content3.AddStream(stream2); |
| + content3.set_rtp_header_extensions(extensions2); |
| + EXPECT_TRUE(channel2_->SetLocalContent(&content3, CA_OFFER, NULL)); |
| + ASSERT_EQ(1u, media_channel2_->send_streams().size()); |
| + EXPECT_EQ(stream2, media_channel2_->send_streams()[0]); |
| + |
| + EXPECT_TRUE(channel1_->SetRemoteContent(&content3, CA_OFFER, NULL)); |
| + ASSERT_EQ(1u, media_channel1_->recv_streams().size()); |
| + EXPECT_EQ(stream2, media_channel1_->recv_streams()[0]); |
| + |
| + // Channel 2 is already sending the new encrypted extensions. These |
| + // can be decrypted by channel 1. Channel 1 is still sending the old |
| + // encrypted extensions (which can be decrypted by channel 2). |
| + packet_listener1.encrypted_headers.clear(); |
| + packet_listener1.encrypted_headers.push_back(2); |
| + packet_listener1.encrypted_headers.push_back(4); |
| + |
| + if (flags & DTLS) { |
| + // DTLS supports updating the encrypted extensions with only the OFFER |
| + // being processed. For SDES both the OFFER and ANSWER must have been |
| + // processed to update encrypted extensions, so we can't check this case. |
| + SendCustomRtp1(kSsrc1, 0); |
| + SendCustomRtp2(kSsrc2, 0); |
| + WaitForThreads(); |
| + EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0)); |
| + EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0)); |
| + } |
| + |
| + // Channel 1 replies with the same extensions. |
| + typename T::Content content4; |
| + CreateContent(content_flags, kPcmuCodec, kH264Codec, &content4); |
| + content4.AddStream(stream1); |
| + content4.set_rtp_header_extensions(extensions2); |
| + EXPECT_TRUE(channel1_->SetLocalContent(&content4, CA_ANSWER, NULL)); |
| + EXPECT_EQ(1u, media_channel1_->send_streams().size()); |
| + |
| + EXPECT_TRUE(channel2_->SetRemoteContent(&content4, CA_ANSWER, NULL)); |
| + EXPECT_EQ(1u, media_channel2_->recv_streams().size()); |
| + |
| + packet_listener2.encrypted_headers.clear(); |
| + packet_listener2.encrypted_headers.push_back(2); |
| + packet_listener2.encrypted_headers.push_back(4); |
| + |
| + SendCustomRtp1(kSsrc1, 0); |
| + SendCustomRtp2(kSsrc2, 0); |
| + WaitForThreads(); |
| + EXPECT_TRUE(CheckCustomRtp2(kSsrc1, 0)); |
| + EXPECT_TRUE(CheckCustomRtp1(kSsrc2, 0)); |
| + } |
| + |
| // Test that we only start playout and sending at the right times. |
| void TestPlayoutAndSendingStates() { |
| CreateChannels(0, 0); |
| @@ -2108,6 +2293,24 @@ class VoiceChannelDoubleThreadTest : public ChannelTest<VoiceTraits> { |
| : Base(true, kPcmuFrame, kRtcpReport, NetworkIsWorker::No) {} |
| }; |
| +class VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest |
| + : public ChannelTest<VoiceTraits> { |
| + public: |
| + typedef ChannelTest<VoiceTraits> Base; |
| + VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest() |
| + : Base(true, kPcmuFrameWithExtensions, kRtcpReport, |
| + NetworkIsWorker::Yes) {} |
| +}; |
| + |
| +class VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest |
| + : public ChannelTest<VoiceTraits> { |
| + public: |
| + typedef ChannelTest<VoiceTraits> Base; |
| + VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest() |
| + : Base(true, kPcmuFrameWithExtensions, kRtcpReport, |
| + NetworkIsWorker::No) {} |
| +}; |
| + |
| // override to add NULL parameter |
| template <> |
| cricket::VideoChannel* ChannelTest<VideoTraits>::CreateChannel( |
| @@ -2247,6 +2450,38 @@ TEST_F(VoiceChannelSingleThreadTest, TestChangeStreamParamsInContent) { |
| Base::TestChangeStreamParamsInContent(); |
| } |
| +TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, |
| + TestChangeEncryptedHeaderExtensionsDtls) { |
| + int flags = DTLS; |
| + Base::TestChangeEncryptedHeaderExtensions(flags); |
| +} |
| + |
| +TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, |
| + TestChangeEncryptedHeaderExtensionsDtlsAsymmetric) { |
| + int flags = DTLS; |
| + bool asymmetric = true; |
| + Base::TestChangeEncryptedHeaderExtensions(flags, asymmetric); |
| +} |
| + |
| +TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, |
| + TestChangeEncryptedHeaderExtensionsDtlsGcm) { |
| + int flags = DTLS | GCM_CIPHER; |
| + Base::TestChangeEncryptedHeaderExtensions(flags); |
| +} |
| + |
| +TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, |
| + TestChangeEncryptedHeaderExtensionsDtlsGcmAsymmetric) { |
| + int flags = DTLS | GCM_CIPHER; |
| + bool asymmetric = true; |
| + Base::TestChangeEncryptedHeaderExtensions(flags, asymmetric); |
| +} |
| + |
| +TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsSingleThreadTest, |
| + TestChangeEncryptedHeaderExtensionsSDES) { |
| + int flags = 0; |
| + Base::TestChangeEncryptedHeaderExtensions(flags); |
| +} |
| + |
| TEST_F(VoiceChannelSingleThreadTest, TestPlayoutAndSendingStates) { |
| Base::TestPlayoutAndSendingStates(); |
| } |
| @@ -2580,6 +2815,38 @@ TEST_F(VoiceChannelDoubleThreadTest, TestChangeStreamParamsInContent) { |
| Base::TestChangeStreamParamsInContent(); |
| } |
| +TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, |
| + TestChangeEncryptedHeaderExtensionsDtls) { |
| + int flags = DTLS; |
| + Base::TestChangeEncryptedHeaderExtensions(flags); |
| +} |
| + |
| +TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, |
| + TestChangeEncryptedHeaderExtensionsDtlsAsymmetric) { |
| + int flags = DTLS; |
| + bool asymmetric = true; |
| + Base::TestChangeEncryptedHeaderExtensions(flags, asymmetric); |
| +} |
| + |
| +TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, |
| + TestChangeEncryptedHeaderExtensionsDtlsGcm) { |
| + int flags = DTLS | GCM_CIPHER; |
| + Base::TestChangeEncryptedHeaderExtensions(flags); |
| +} |
| + |
| +TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, |
| + TestChangeEncryptedHeaderExtensionsDtlsGcmAsymmetric) { |
| + int flags = DTLS | GCM_CIPHER; |
| + bool asymmetric = true; |
| + Base::TestChangeEncryptedHeaderExtensions(flags, asymmetric); |
| +} |
| + |
| +TEST_F(VoiceChannelWithEncryptedRtpHeaderExtensionsDoubleThreadTest, |
| + TestChangeEncryptedHeaderExtensionsSDES) { |
| + int flags = 0; |
| + Base::TestChangeEncryptedHeaderExtensions(flags); |
| +} |
| + |
| TEST_F(VoiceChannelDoubleThreadTest, TestPlayoutAndSendingStates) { |
| Base::TestPlayoutAndSendingStates(); |
| } |