Make ChannelInterface::Enabled() be async.

* Changing return value from bool to void since the operation as async
  effects anyway.
* Removing the `enabled()` accessor due to potential threading issues
  and potential TOCTOU issues. It was only used in one place anyway.
* Applying thread restrictions to member variables.

Bug: none
Change-Id: I51949f5594339952d7b717cfd82f99b532e86b23
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/216182
Commit-Queue: Tommi <tommi@webrtc.org>
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#33830}
This commit is contained in:
Tommi
2021-04-26 10:20:19 +02:00
committed by Commit Bot
parent 448d18b18d
commit 1959f8fedc
6 changed files with 35 additions and 21 deletions

View File

@ -271,16 +271,25 @@ bool BaseChannel::SetRtpTransport(webrtc::RtpTransportInternal* rtp_transport) {
return true; return true;
} }
bool BaseChannel::Enable(bool enable) { void BaseChannel::Enable(bool enable) {
worker_thread_->Invoke<void>(RTC_FROM_HERE, [this, enable] { RTC_DCHECK_RUN_ON(signaling_thread());
if (enable == enabled_s_)
return;
enabled_s_ = enable;
worker_thread_->PostTask(ToQueuedTask(alive_, [this, enable] {
RTC_DCHECK_RUN_ON(worker_thread()); RTC_DCHECK_RUN_ON(worker_thread());
// Sanity check to make sure that enabled_ and enabled_s_
// stay in sync.
RTC_DCHECK_NE(enabled_, enable);
if (enable) { if (enable) {
EnableMedia_w(); EnableMedia_w();
} else { } else {
DisableMedia_w(); DisableMedia_w();
} }
}); }));
return true;
} }
bool BaseChannel::SetLocalContent(const MediaContentDescription* content, bool BaseChannel::SetLocalContent(const MediaContentDescription* content,
@ -313,14 +322,14 @@ bool BaseChannel::SetPayloadTypeDemuxingEnabled(bool enabled) {
bool BaseChannel::IsReadyToReceiveMedia_w() const { bool BaseChannel::IsReadyToReceiveMedia_w() const {
// Receive data if we are enabled and have local content, // Receive data if we are enabled and have local content,
return enabled() && return enabled_ &&
webrtc::RtpTransceiverDirectionHasRecv(local_content_direction_); webrtc::RtpTransceiverDirectionHasRecv(local_content_direction_);
} }
bool BaseChannel::IsReadyToSendMedia_w() const { bool BaseChannel::IsReadyToSendMedia_w() const {
// Send outgoing data if we are enabled, have local and remote content, // Send outgoing data if we are enabled, have local and remote content,
// and we have had some form of connectivity. // and we have had some form of connectivity.
return enabled() && return enabled_ &&
webrtc::RtpTransceiverDirectionHasRecv(remote_content_direction_) && webrtc::RtpTransceiverDirectionHasRecv(remote_content_direction_) &&
webrtc::RtpTransceiverDirectionHasSend(local_content_direction_) && webrtc::RtpTransceiverDirectionHasSend(local_content_direction_) &&
was_ever_writable(); was_ever_writable();

View File

@ -131,7 +131,6 @@ class BaseChannel : public ChannelInterface,
// TODO(tommi): Delete this variable. // TODO(tommi): Delete this variable.
return transport_name_; return transport_name_;
} }
bool enabled() const override { return enabled_; }
// This function returns true if using SRTP (DTLS-based keying or SDES). // This function returns true if using SRTP (DTLS-based keying or SDES).
bool srtp_active() const { bool srtp_active() const {
@ -167,7 +166,7 @@ class BaseChannel : public ChannelInterface,
// actually belong to a new channel. See: crbug.com/webrtc/11477 // actually belong to a new channel. See: crbug.com/webrtc/11477
bool SetPayloadTypeDemuxingEnabled(bool enabled) override; bool SetPayloadTypeDemuxingEnabled(bool enabled) override;
bool Enable(bool enable) override; void Enable(bool enable) override;
const std::vector<StreamParams>& local_streams() const override { const std::vector<StreamParams>& local_streams() const override {
return local_streams_; return local_streams_;
@ -356,7 +355,8 @@ class BaseChannel : public ChannelInterface,
// Currently the |enabled_| flag is accessed from the signaling thread as // Currently the |enabled_| flag is accessed from the signaling thread as
// well, but it can be changed only when signaling thread does a synchronous // well, but it can be changed only when signaling thread does a synchronous
// call to the worker thread, so it should be safe. // call to the worker thread, so it should be safe.
bool enabled_ = false; bool enabled_ RTC_GUARDED_BY(worker_thread()) = false;
bool enabled_s_ RTC_GUARDED_BY(signaling_thread()) = false;
bool payload_type_demuxing_enabled_ RTC_GUARDED_BY(worker_thread()) = true; bool payload_type_demuxing_enabled_ RTC_GUARDED_BY(worker_thread()) = true;
std::vector<StreamParams> local_streams_ RTC_GUARDED_BY(worker_thread()); std::vector<StreamParams> local_streams_ RTC_GUARDED_BY(worker_thread());
std::vector<StreamParams> remote_streams_ RTC_GUARDED_BY(worker_thread()); std::vector<StreamParams> remote_streams_ RTC_GUARDED_BY(worker_thread());

View File

@ -37,10 +37,8 @@ class ChannelInterface {
virtual const std::string& content_name() const = 0; virtual const std::string& content_name() const = 0;
virtual bool enabled() const = 0;
// Enables or disables this channel // Enables or disables this channel
virtual bool Enable(bool enable) = 0; virtual void Enable(bool enable) = 0;
// Used for latency measurements. // Used for latency measurements.
virtual sigslot::signal1<ChannelInterface*>& SignalFirstPacketReceived() = 0; virtual sigslot::signal1<ChannelInterface*>& SignalFirstPacketReceived() = 0;

View File

@ -336,6 +336,7 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
SdpType::kOffer, NULL); SdpType::kOffer, NULL);
if (result) { if (result) {
channel1_->Enable(true); channel1_->Enable(true);
FlushCurrentThread();
result = channel2_->SetRemoteContent(&remote_media_content1_, result = channel2_->SetRemoteContent(&remote_media_content1_,
SdpType::kOffer, NULL); SdpType::kOffer, NULL);
if (result) { if (result) {
@ -349,6 +350,7 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
bool SendAccept() { bool SendAccept() {
channel2_->Enable(true); channel2_->Enable(true);
FlushCurrentThread();
return channel1_->SetRemoteContent(&remote_media_content2_, return channel1_->SetRemoteContent(&remote_media_content2_,
SdpType::kAnswer, NULL); SdpType::kAnswer, NULL);
} }
@ -633,7 +635,7 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
CreateContent(0, kPcmuCodec, kH264Codec, &content1); CreateContent(0, kPcmuCodec, kH264Codec, &content1);
content1.AddStream(stream1); content1.AddStream(stream1);
EXPECT_TRUE(channel1_->SetLocalContent(&content1, SdpType::kOffer, NULL)); EXPECT_TRUE(channel1_->SetLocalContent(&content1, SdpType::kOffer, NULL));
EXPECT_TRUE(channel1_->Enable(true)); channel1_->Enable(true);
EXPECT_EQ(1u, media_channel1_->send_streams().size()); EXPECT_EQ(1u, media_channel1_->send_streams().size());
EXPECT_TRUE(channel2_->SetRemoteContent(&content1, SdpType::kOffer, NULL)); EXPECT_TRUE(channel2_->SetRemoteContent(&content1, SdpType::kOffer, NULL));
@ -646,7 +648,7 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
EXPECT_TRUE(channel1_->SetRemoteContent(&content2, SdpType::kAnswer, NULL)); EXPECT_TRUE(channel1_->SetRemoteContent(&content2, SdpType::kAnswer, NULL));
EXPECT_EQ(0u, media_channel1_->recv_streams().size()); EXPECT_EQ(0u, media_channel1_->recv_streams().size());
EXPECT_TRUE(channel2_->SetLocalContent(&content2, SdpType::kAnswer, NULL)); EXPECT_TRUE(channel2_->SetLocalContent(&content2, SdpType::kAnswer, NULL));
EXPECT_TRUE(channel2_->Enable(true)); channel2_->Enable(true);
EXPECT_EQ(0u, media_channel2_->send_streams().size()); EXPECT_EQ(0u, media_channel2_->send_streams().size());
SendCustomRtp1(kSsrc1, 0); SendCustomRtp1(kSsrc1, 0);
@ -690,7 +692,8 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
EXPECT_FALSE(media_channel2_->playout()); EXPECT_FALSE(media_channel2_->playout());
} }
EXPECT_FALSE(media_channel2_->sending()); EXPECT_FALSE(media_channel2_->sending());
EXPECT_TRUE(channel1_->Enable(true)); channel1_->Enable(true);
FlushCurrentThread();
if (verify_playout_) { if (verify_playout_) {
EXPECT_FALSE(media_channel1_->playout()); EXPECT_FALSE(media_channel1_->playout());
} }
@ -722,7 +725,8 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
EXPECT_FALSE(media_channel2_->playout()); EXPECT_FALSE(media_channel2_->playout());
} }
EXPECT_FALSE(media_channel2_->sending()); EXPECT_FALSE(media_channel2_->sending());
EXPECT_TRUE(channel2_->Enable(true)); channel2_->Enable(true);
FlushCurrentThread();
if (verify_playout_) { if (verify_playout_) {
EXPECT_TRUE(media_channel2_->playout()); EXPECT_TRUE(media_channel2_->playout());
} }
@ -746,8 +750,9 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
// Set |content2| to be InActive. // Set |content2| to be InActive.
content2.set_direction(RtpTransceiverDirection::kInactive); content2.set_direction(RtpTransceiverDirection::kInactive);
EXPECT_TRUE(channel1_->Enable(true)); channel1_->Enable(true);
EXPECT_TRUE(channel2_->Enable(true)); channel2_->Enable(true);
FlushCurrentThread();
if (verify_playout_) { if (verify_playout_) {
EXPECT_FALSE(media_channel1_->playout()); EXPECT_FALSE(media_channel1_->playout());
} }
@ -1365,6 +1370,9 @@ class ChannelTest : public ::testing::Test, public sigslot::has_slots<> {
thread->ProcessMessages(0); thread->ProcessMessages(0);
} }
} }
static void FlushCurrentThread() {
rtc::Thread::Current()->ProcessMessages(0);
}
void WaitForThreads(rtc::ArrayView<rtc::Thread*> threads) { void WaitForThreads(rtc::ArrayView<rtc::Thread*> threads) {
// |threads| and current thread post packets to network thread. // |threads| and current thread post packets to network thread.
for (rtc::Thread* thread : threads) { for (rtc::Thread* thread : threads) {

View File

@ -4137,7 +4137,7 @@ void SdpOfferAnswerHandler::EnableSending() {
RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK_RUN_ON(signaling_thread());
for (const auto& transceiver : transceivers()->ListInternal()) { for (const auto& transceiver : transceivers()->ListInternal()) {
cricket::ChannelInterface* channel = transceiver->channel(); cricket::ChannelInterface* channel = transceiver->channel();
if (channel && !channel->enabled()) { if (channel) {
channel->Enable(true); channel->Enable(true);
} }
} }

View File

@ -28,8 +28,7 @@ class MockChannelInterface : public cricket::ChannelInterface {
MOCK_METHOD(MediaChannel*, media_channel, (), (const, override)); MOCK_METHOD(MediaChannel*, media_channel, (), (const, override));
MOCK_METHOD(const std::string&, transport_name, (), (const, override)); MOCK_METHOD(const std::string&, transport_name, (), (const, override));
MOCK_METHOD(const std::string&, content_name, (), (const, override)); MOCK_METHOD(const std::string&, content_name, (), (const, override));
MOCK_METHOD(bool, enabled, (), (const, override)); MOCK_METHOD(void, Enable, (bool), (override));
MOCK_METHOD(bool, Enable, (bool), (override));
MOCK_METHOD(sigslot::signal1<ChannelInterface*>&, MOCK_METHOD(sigslot::signal1<ChannelInterface*>&,
SignalFirstPacketReceived, SignalFirstPacketReceived,
(), (),