Index: talk/session/media/channel.cc |
diff --git a/talk/session/media/channel.cc b/talk/session/media/channel.cc |
index f83afa1ea46434352abc18abe22d9ba70cd83318..a25ab7d0df682791ec5b4abc0d07f4efae3166df 100644 |
--- a/talk/session/media/channel.cc |
+++ b/talk/session/media/channel.cc |
@@ -249,6 +249,13 @@ bool BaseChannel::SetTransport_w(const std::string& transport_name) { |
return true; |
} |
+ // When using DTLS-SRTP, we must reset the SrtpFilter every time the transport |
+ // changes and wait until the DTLS handshake is complete to set the newly |
+ // negotiated parameters. |
+ if (ShouldSetupDtlsSrtp()) { |
+ srtp_filter_.ResetParams(); |
+ } |
+ |
set_transport_channel(transport_controller_->CreateTransportChannel_w( |
transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP)); |
if (!transport_channel()) { |
@@ -318,6 +325,9 @@ void BaseChannel::set_rtcp_transport_channel(TransportChannel* new_tc) { |
rtcp_transport_channel_ = new_tc; |
if (new_tc) { |
+ RTC_CHECK(!(ShouldSetupDtlsSrtp() && srtp_filter_.IsActive())) |
+ << "Setting RTCP for DTLS/SRTP after SrtpFilter is active " |
+ << "should never happen."; |
ConnectToTransportChannel(new_tc); |
for (const auto& pair : rtcp_socket_options_) { |
new_tc->SetOption(pair.first, pair.second); |
@@ -336,6 +346,7 @@ void BaseChannel::ConnectToTransportChannel(TransportChannel* tc) { |
tc->SignalWritableState.connect(this, &BaseChannel::OnWritableState); |
tc->SignalReadPacket.connect(this, &BaseChannel::OnChannelRead); |
tc->SignalReadyToSend.connect(this, &BaseChannel::OnReadyToSend); |
+ tc->SignalDtlsState.connect(this, &BaseChannel::OnDtlsState); |
} |
void BaseChannel::DisconnectFromTransportChannel(TransportChannel* tc) { |
@@ -344,6 +355,7 @@ void BaseChannel::DisconnectFromTransportChannel(TransportChannel* tc) { |
tc->SignalWritableState.disconnect(this); |
tc->SignalReadPacket.disconnect(this); |
tc->SignalReadyToSend.disconnect(this); |
+ tc->SignalDtlsState.disconnect(this); |
} |
bool BaseChannel::Enable(bool enable) { |
@@ -416,10 +428,10 @@ bool BaseChannel::IsReadyToReceive() const { |
bool BaseChannel::IsReadyToSend() const { |
// Send outgoing data if we are enabled, have local and remote content, |
// and we have had some form of connectivity. |
- return enabled() && |
- IsReceiveContentDirection(remote_content_direction_) && |
+ return enabled() && IsReceiveContentDirection(remote_content_direction_) && |
IsSendContentDirection(local_content_direction_) && |
- was_ever_writable(); |
+ was_ever_writable() && |
+ (srtp_filter_.IsActive() || !ShouldSetupDtlsSrtp()); |
} |
bool BaseChannel::SendPacket(rtc::Buffer* packet, |
@@ -474,6 +486,22 @@ void BaseChannel::OnReadyToSend(TransportChannel* channel) { |
SetReadyToSend(channel == rtcp_transport_channel_, true); |
} |
+void BaseChannel::OnDtlsState(TransportChannel* channel, |
+ DtlsTransportState state) { |
+ if (!ShouldSetupDtlsSrtp()) { |
+ return; |
+ } |
+ |
+ // Reset the srtp filter if it's not the CONNECTED state. For the CONNECTED |
+ // state, setting up DTLS-SRTP context is deferred to ChannelWritable_w to |
+ // cover other scenarios like the whole channel is writable (not just this |
+ // TransportChannel) or when TransportChannel is attached after DTLS is |
+ // negotiated. |
+ if (state != DTLS_TRANSPORT_CONNECTED) { |
+ srtp_filter_.ResetParams(); |
+ } |
+} |
+ |
void BaseChannel::SetReadyToSend(bool rtcp, bool ready) { |
if (rtcp) { |
rtcp_ready_to_send_ = ready; |
@@ -761,8 +789,9 @@ void BaseChannel::UpdateWritableState_w() { |
void BaseChannel::ChannelWritable_w() { |
ASSERT(worker_thread_ == rtc::Thread::Current()); |
- if (writable_) |
+ if (writable_) { |
return; |
+ } |
LOG(LS_INFO) << "Channel writable (" << content_name_ << ")" |
<< (was_ever_writable_ ? "" : " for the first time"); |
@@ -778,22 +807,8 @@ void BaseChannel::ChannelWritable_w() { |
} |
} |
- // If we're doing DTLS-SRTP, now is the time. |
- if (!was_ever_writable_ && ShouldSetupDtlsSrtp()) { |
- if (!SetupDtlsSrtp(false)) { |
- SignalDtlsSetupFailure_w(false); |
- return; |
- } |
- |
- if (rtcp_transport_channel_) { |
- if (!SetupDtlsSrtp(true)) { |
- SignalDtlsSetupFailure_w(true); |
- return; |
- } |
- } |
- } |
- |
was_ever_writable_ = true; |
+ MaybeSetupDtlsSrtp_w(); |
writable_ = true; |
ChangeState(); |
} |
@@ -822,7 +837,8 @@ bool BaseChannel::SetDtlsSrtpCryptoSuites(TransportChannel* tc, bool rtcp) { |
} |
bool BaseChannel::ShouldSetupDtlsSrtp() const { |
- return true; |
+ // Since DTLS is applied to all channels, checking RTP should be enough. |
+ return transport_channel_ && transport_channel_->IsDtlsActive(); |
} |
// This function returns true if either DTLS-SRTP is not in use |
@@ -833,9 +849,7 @@ bool BaseChannel::SetupDtlsSrtp(bool rtcp_channel) { |
TransportChannel* channel = |
rtcp_channel ? rtcp_transport_channel_ : transport_channel_; |
- // No DTLS |
- if (!channel->IsDtlsActive()) |
- return true; |
+ RTC_DCHECK(channel->IsDtlsActive()); |
int selected_crypto_suite; |
@@ -915,6 +929,28 @@ bool BaseChannel::SetupDtlsSrtp(bool rtcp_channel) { |
return ret; |
} |
+void BaseChannel::MaybeSetupDtlsSrtp_w() { |
+ if (srtp_filter_.IsActive()) { |
+ return; |
+ } |
+ |
+ if (!ShouldSetupDtlsSrtp()) { |
+ return; |
+ } |
+ |
+ if (!SetupDtlsSrtp(false)) { |
+ SignalDtlsSetupFailure_w(false); |
+ return; |
+ } |
+ |
+ if (rtcp_transport_channel_) { |
+ if (!SetupDtlsSrtp(true)) { |
+ SignalDtlsSetupFailure_w(true); |
+ return; |
+ } |
+ } |
+} |
+ |
void BaseChannel::ChannelNotWritable_w() { |
ASSERT(worker_thread_ == rtc::Thread::Current()); |
if (!writable_) |
@@ -2263,7 +2299,7 @@ void DataChannel::GetSrtpCryptoSuites(std::vector<int>* crypto_suites) const { |
} |
bool DataChannel::ShouldSetupDtlsSrtp() const { |
- return (data_channel_type_ == DCT_RTP); |
+ return (data_channel_type_ == DCT_RTP) && BaseChannel::ShouldSetupDtlsSrtp(); |
} |
void DataChannel::OnStreamClosedRemotely(uint32_t sid) { |