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

View File

@ -131,7 +131,6 @@ class BaseChannel : public ChannelInterface,
// TODO(tommi): Delete this variable.
return transport_name_;
}
bool enabled() const override { return enabled_; }
// This function returns true if using SRTP (DTLS-based keying or SDES).
bool srtp_active() const {
@ -167,7 +166,7 @@ class BaseChannel : public ChannelInterface,
// actually belong to a new channel. See: crbug.com/webrtc/11477
bool SetPayloadTypeDemuxingEnabled(bool enabled) override;
bool Enable(bool enable) override;
void Enable(bool enable) override;
const std::vector<StreamParams>& local_streams() const override {
return local_streams_;
@ -356,7 +355,8 @@ class BaseChannel : public ChannelInterface,
// Currently the |enabled_| flag is accessed from the signaling thread as
// well, but it can be changed only when signaling thread does a synchronous
// 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;
std::vector<StreamParams> local_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 bool enabled() const = 0;
// Enables or disables this channel
virtual bool Enable(bool enable) = 0;
virtual void Enable(bool enable) = 0;
// Used for latency measurements.
virtual sigslot::signal1<ChannelInterface*>& SignalFirstPacketReceived() = 0;

View File

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

View File

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

View File

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