Skip to content

Commit ecab2a4

Browse files
fippoWebRTC LUCI CQ
authored andcommitted
[m114] Attempt to recycle a stopped data m-line before creating a new one
which avoids an infinitely growing SDP if the remote end rejects the datachannel section. This will reactivate the m-line even if all datachannels are closed. BUG=chromium:1442604 (cherry picked from commit 522380f) No-Try: True Change-Id: If60f93b406271163df692d96102baab701923602 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/304241 Reviewed-by: Harald Alvestrand <[email protected]> Commit-Queue: Philipp Hancke <[email protected]> Reviewed-by: Henrik Boström <[email protected]> Cr-Original-Commit-Position: refs/heads/main@{#40029} Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/305420 Commit-Queue: Harald Alvestrand <[email protected]> Reviewed-by: Mirko Bonadei <[email protected]> Cr-Commit-Position: refs/branch-heads/5735@{#2} Cr-Branched-From: df7df19-refs/heads/main@{#39949}
1 parent 9d99682 commit ecab2a4

File tree

6 files changed

+126
-14
lines changed

6 files changed

+126
-14
lines changed

pc/data_channel_controller.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ DataChannelController::~DataChannelController() {
2828
<< "Missing call to PrepareForShutdown?";
2929
}
3030

31-
bool DataChannelController::HasDataChannelsForTest() const {
31+
bool DataChannelController::HasDataChannels() const {
3232
auto has_channels = [&] {
3333
RTC_DCHECK_RUN_ON(network_thread());
3434
return !sctp_data_channels_n_.empty();

pc/data_channel_controller.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,9 @@ class DataChannelController : public SctpDataChannelControllerInterface,
8787
const InternalDataChannelInit& config);
8888
void AllocateSctpSids(rtc::SSLRole role);
8989

90-
// Used by tests to check if data channels are currently tracked.
91-
bool HasDataChannelsForTest() const;
90+
// Check if data channels are currently tracked. Used to decide whether a
91+
// rejected m=application section should be reoffered.
92+
bool HasDataChannels() const;
9293

9394
// At some point in time, a data channel has existed.
9495
bool HasUsedDataChannels() const;

pc/data_channel_controller_unittest.cc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,17 @@ TEST_F(DataChannelControllerTest, CreateDataChannelEarlyRelease) {
105105

106106
TEST_F(DataChannelControllerTest, CreateDataChannelEarlyClose) {
107107
DataChannelControllerForTest dcc(pc_.get());
108-
EXPECT_FALSE(dcc.HasDataChannelsForTest());
108+
EXPECT_FALSE(dcc.HasDataChannels());
109109
EXPECT_FALSE(dcc.HasUsedDataChannels());
110110
auto ret = dcc.InternalCreateDataChannelWithProxy(
111111
"label", InternalDataChannelInit(DataChannelInit()));
112112
ASSERT_TRUE(ret.ok());
113113
auto channel = ret.MoveValue();
114-
EXPECT_TRUE(dcc.HasDataChannelsForTest());
114+
EXPECT_TRUE(dcc.HasDataChannels());
115115
EXPECT_TRUE(dcc.HasUsedDataChannels());
116116
channel->Close();
117117
run_loop_.Flush();
118-
EXPECT_FALSE(dcc.HasDataChannelsForTest());
118+
EXPECT_FALSE(dcc.HasDataChannels());
119119
EXPECT_TRUE(dcc.HasUsedDataChannels());
120120
}
121121

pc/peer_connection.cc

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1422,9 +1422,10 @@ PeerConnection::CreateDataChannelOrError(const std::string& label,
14221422

14231423
rtc::scoped_refptr<DataChannelInterface> channel = ret.MoveValue();
14241424

1425-
// Trigger the onRenegotiationNeeded event for
1426-
// the first SCTP DataChannel.
1427-
if (first_datachannel) {
1425+
// Check the onRenegotiationNeeded event (with plan-b backward compat)
1426+
if (configuration_.sdp_semantics == SdpSemantics::kUnifiedPlan ||
1427+
(configuration_.sdp_semantics == SdpSemantics::kPlanB_DEPRECATED &&
1428+
first_datachannel)) {
14281429
sdp_handler_->UpdateNegotiationNeeded();
14291430
}
14301431
NoteUsageEvent(UsageEvent::DATA_ADDED);

pc/sdp_offer_answer.cc

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3342,8 +3342,20 @@ bool SdpOfferAnswerHandler::CheckIfNegotiationIsNeeded() {
33423342
// 4. If connection has created any RTCDataChannels, and no m= section in
33433343
// description has been negotiated yet for data, return true.
33443344
if (data_channel_controller()->HasUsedDataChannels()) {
3345-
if (!cricket::GetFirstDataContent(description->description()->contents()))
3345+
const cricket::ContentInfo* data_content =
3346+
cricket::GetFirstDataContent(description->description()->contents());
3347+
if (!data_content) {
33463348
return true;
3349+
}
3350+
// The remote end might have rejected the data content.
3351+
const cricket::ContentInfo* remote_data_content =
3352+
current_remote_description()
3353+
? current_remote_description()->description()->GetContentByName(
3354+
data_content->name)
3355+
: nullptr;
3356+
if (remote_data_content && remote_data_content->rejected) {
3357+
return true;
3358+
}
33473359
}
33483360
if (!ConfiguredForMedia()) {
33493361
return false;
@@ -4263,10 +4275,28 @@ void SdpOfferAnswerHandler::GetOptionsForUnifiedPlanOffer(
42634275
}
42644276
// Lastly, add a m-section if we have requested local data channels and an
42654277
// m section does not already exist.
4266-
if (!pc_->GetDataMid() && data_channel_controller()->HasUsedDataChannels()) {
4267-
session_options->media_description_options.push_back(
4268-
GetMediaDescriptionOptionsForActiveData(
4269-
mid_generator_.GenerateString()));
4278+
if (!pc_->GetDataMid() && data_channel_controller()->HasUsedDataChannels() &&
4279+
data_channel_controller()->HasDataChannels()) {
4280+
// Attempt to recycle a stopped m-line.
4281+
// TODO(crbug.com/1442604): GetDataMid() should return the mid if one was
4282+
// ever created but rejected.
4283+
bool recycled = false;
4284+
for (size_t i = 0; i < session_options->media_description_options.size();
4285+
i++) {
4286+
auto media_description = session_options->media_description_options[i];
4287+
if (media_description.type == cricket::MEDIA_TYPE_DATA &&
4288+
media_description.stopped) {
4289+
session_options->media_description_options[i] =
4290+
GetMediaDescriptionOptionsForActiveData(media_description.mid);
4291+
recycled = true;
4292+
break;
4293+
}
4294+
}
4295+
if (!recycled) {
4296+
session_options->media_description_options.push_back(
4297+
GetMediaDescriptionOptionsForActiveData(
4298+
mid_generator_.GenerateString()));
4299+
}
42704300
}
42714301
}
42724302

pc/sdp_offer_answer_unittest.cc

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "modules/audio_processing/include/audio_processing.h"
3535
#include "p2p/base/port_allocator.h"
3636
#include "pc/peer_connection_wrapper.h"
37+
#include "pc/session_description.h"
3738
#include "pc/test/fake_audio_capture_module.h"
3839
#include "pc/test/mock_peer_connection_observers.h"
3940
#include "rtc_base/rtc_certificate_generator.h"
@@ -467,4 +468,83 @@ TEST_F(SdpOfferAnswerTest, RollbackPreservesAddTrackMid) {
467468
EXPECT_EQ(saved_mid, first_transceiver->mid());
468469
}
469470

471+
#ifdef WEBRTC_HAVE_SCTP
472+
473+
TEST_F(SdpOfferAnswerTest, RejectedDataChannelsDoNotGetReoffered) {
474+
auto pc = CreatePeerConnection();
475+
EXPECT_TRUE(pc->pc()->CreateDataChannelOrError("dc", nullptr).ok());
476+
EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
477+
auto mid = pc->pc()->local_description()->description()->contents()[0].mid();
478+
479+
// An answer that rejects the datachannel content.
480+
std::string sdp =
481+
"v=0\r\n"
482+
"o=- 4131505339648218884 3 IN IP4 **-----**\r\n"
483+
"s=-\r\n"
484+
"t=0 0\r\n"
485+
"a=ice-ufrag:zGWFZ+fVXDeN6UoI/136\r\n"
486+
"a=ice-pwd:9AUNgUqRNI5LSIrC1qFD2iTR\r\n"
487+
"a=fingerprint:sha-256 "
488+
"AD:52:52:E0:B1:37:34:21:0E:15:8E:B7:56:56:7B:B4:39:0E:6D:1C:F5:84:A7:EE:"
489+
"B5:27:3E:30:B1:7D:69:42\r\n"
490+
"a=setup:passive\r\n"
491+
"m=application 0 UDP/DTLS/SCTP webrtc-datachannel\r\n"
492+
"c=IN IP4 0.0.0.0\r\n"
493+
"a=sctp-port:5000\r\n"
494+
"a=max-message-size:262144\r\n"
495+
"a=mid:" +
496+
mid + "\r\n";
497+
auto answer = CreateSessionDescription(SdpType::kAnswer, sdp);
498+
ASSERT_TRUE(pc->SetRemoteDescription(std::move(answer)));
499+
// The subsequent offer should not recycle the m-line since the existing data
500+
// channel is closed.
501+
auto offer = pc->CreateOffer();
502+
const auto& offer_contents = offer->description()->contents();
503+
ASSERT_EQ(offer_contents.size(), 1u);
504+
EXPECT_EQ(offer_contents[0].mid(), mid);
505+
EXPECT_EQ(offer_contents[0].rejected, true);
506+
}
507+
508+
TEST_F(SdpOfferAnswerTest, RejectedDataChannelsDoGetReofferedWhenActive) {
509+
auto pc = CreatePeerConnection();
510+
EXPECT_TRUE(pc->pc()->CreateDataChannelOrError("dc", nullptr).ok());
511+
EXPECT_TRUE(pc->CreateOfferAndSetAsLocal());
512+
auto mid = pc->pc()->local_description()->description()->contents()[0].mid();
513+
514+
// An answer that rejects the datachannel content.
515+
std::string sdp =
516+
"v=0\r\n"
517+
"o=- 4131505339648218884 3 IN IP4 **-----**\r\n"
518+
"s=-\r\n"
519+
"t=0 0\r\n"
520+
"a=ice-ufrag:zGWFZ+fVXDeN6UoI/136\r\n"
521+
"a=ice-pwd:9AUNgUqRNI5LSIrC1qFD2iTR\r\n"
522+
"a=fingerprint:sha-256 "
523+
"AD:52:52:E0:B1:37:34:21:0E:15:8E:B7:56:56:7B:B4:39:0E:6D:1C:F5:84:A7:EE:"
524+
"B5:27:3E:30:B1:7D:69:42\r\n"
525+
"a=setup:passive\r\n"
526+
"m=application 0 UDP/DTLS/SCTP webrtc-datachannel\r\n"
527+
"c=IN IP4 0.0.0.0\r\n"
528+
"a=sctp-port:5000\r\n"
529+
"a=max-message-size:262144\r\n"
530+
"a=mid:" +
531+
mid + "\r\n";
532+
auto answer = CreateSessionDescription(SdpType::kAnswer, sdp);
533+
ASSERT_TRUE(pc->SetRemoteDescription(std::move(answer)));
534+
535+
// The subsequent offer should recycle the m-line when there is a new data
536+
// channel.
537+
EXPECT_TRUE(pc->pc()->CreateDataChannelOrError("dc2", nullptr).ok());
538+
EXPECT_TRUE(pc->pc()->ShouldFireNegotiationNeededEvent(
539+
pc->observer()->latest_negotiation_needed_event()));
540+
541+
auto offer = pc->CreateOffer();
542+
const auto& offer_contents = offer->description()->contents();
543+
ASSERT_EQ(offer_contents.size(), 1u);
544+
EXPECT_EQ(offer_contents[0].mid(), mid);
545+
EXPECT_EQ(offer_contents[0].rejected, false);
546+
}
547+
548+
#endif // WEBRTC_HAVE_SCTP
549+
470550
} // namespace webrtc

0 commit comments

Comments
 (0)