snap: assert behavior when sctp-init changes due to pranswer Also changes the SctpTransport::Start to a blocking call which allows SetRemoteDescription to react to errors such as changing the sctp-init or sctp-port. Bug: webrtc:426480601 Change-Id: Ifa8b97a4bbc055130c15293cda59a33281ad4f80 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/457901 Reviewed-by: Harald Alvestrand <hta@webrtc.org> Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org> Commit-Queue: Philipp Hancke <philipp.hancke@googlemail.com> Cr-Commit-Position: refs/heads/main@{#47237}
diff --git a/pc/data_channel_integrationtest.cc b/pc/data_channel_integrationtest.cc index 3a4b280..cf7a5b7 100644 --- a/pc/data_channel_integrationtest.cc +++ b/pc/data_channel_integrationtest.cc
@@ -1479,8 +1479,7 @@ caller()->CreateAndSetAndSignalOffer(); ASSERT_THAT(answer, NotNull()); - // Currently SRD succeeds. - EXPECT_TRUE(caller()->SetRemoteDescription(std::move(answer))); + EXPECT_FALSE(caller()->SetRemoteDescription(std::move(answer))); // Check the state of the SCTP transport. VerifySctpState(caller(), SctpTransportState::kClosed); }
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc index e2a4ade..6270413 100644 --- a/pc/peer_connection.cc +++ b/pc/peer_connection.cc
@@ -3116,14 +3116,16 @@ RTC_DCHECK_RUN_ON(signaling_thread()); RTC_DCHECK(sctp_mid_s_); - network_thread()->PostTask( - SafeTask(network_thread_safety_, [this, mid = *sctp_mid_s_, options] { - scoped_refptr<SctpTransport> sctp_transport = - transport_controller_n()->GetSctpTransport(mid); - if (sctp_transport) - sctp_transport->Start(options); - })); - return RTCError::OK(); + return network_thread()->BlockingCall([this, mid = *sctp_mid_s_, options] { + scoped_refptr<SctpTransport> sctp_transport = + transport_controller_n()->GetSctpTransport(mid); + RTC_DCHECK(sctp_transport); + if (!sctp_transport || !sctp_transport->Start(options)) { + LOG_AND_RETURN_ERROR(RTCErrorType::INVALID_MODIFICATION, + "Failed to start SCTP transport."); + } + return RTCError::OK(); + }); } CryptoOptions PeerConnection::GetCryptoOptions() {
diff --git a/pc/peer_connection.h b/pc/peer_connection.h index 42387f8..15743e2 100644 --- a/pc/peer_connection.h +++ b/pc/peer_connection.h
@@ -417,8 +417,9 @@ bool CreateDataChannelTransport(absl::string_view mid) override; void DestroyDataChannelTransport(RTCError error) override; - // Asynchronously calls SctpTransport::Start() on the network thread for - // `sctp_mid()` if set. Called as part of setting the local description. + // Synchronously calls SctpTransport::Start() on the network thread for + // `sctp_mid()` if set. Called as part of pushing down the media descriptions + // after a complete offer/answer. RTCError StartSctpTransport(const SctpOptions& options) override; // Returns the CryptoOptions set as RTCConfiguration.crypto_options for this
diff --git a/pc/peer_connection_internal.h b/pc/peer_connection_internal.h index 8314f7b..f31f999 100644 --- a/pc/peer_connection_internal.h +++ b/pc/peer_connection_internal.h
@@ -127,8 +127,9 @@ scoped_refptr<MediaStreamTrackInterface> track, const RtpTransceiverInit& init, bool fire_callback = true) = 0; - // Asynchronously calls SctpTransport::Start() on the network thread for - // `sctp_mid()` if set. Called as part of setting the local description. + // Synchronously calls SctpTransport::Start() on the network thread for + // `sctp_mid()` if set. Called as part of pushing down the media descriptions + // after a complete offer/answer. virtual RTCError StartSctpTransport(const SctpOptions& options) = 0; // Asynchronously adds a remote candidate on the network thread.
diff --git a/pc/sctp_transport.cc b/pc/sctp_transport.cc index 063c855..abca8a1 100644 --- a/pc/sctp_transport.cc +++ b/pc/sctp_transport.cc
@@ -176,7 +176,7 @@ UpdateInformation(SctpTransportState::kClosed); } -void SctpTransport::Start(const SctpOptions& options) { +bool SctpTransport::Start(const SctpOptions& options) { RTC_DCHECK_RUN_ON(owner_thread_); info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(), @@ -185,7 +185,9 @@ if (!internal()->Start(options)) { RTC_LOG(LS_ERROR) << "Failed to push down SCTP parameters, closing."; UpdateInformation(SctpTransportState::kClosed); + return false; } + return true; } void SctpTransport::UpdateInformation(SctpTransportState state) {
diff --git a/pc/sctp_transport.h b/pc/sctp_transport.h index 32014aa..c6908a9 100644 --- a/pc/sctp_transport.h +++ b/pc/sctp_transport.h
@@ -65,9 +65,9 @@ // Internal functions void Clear(); - // Initialize the webrtc::SctpTransport. This can be called from + // Initialize the webrtc::SctpTransport. This must be called from // the signaling thread. - void Start(const SctpOptions& options); + bool Start(const SctpOptions& options); // TODO(https://bugs.webrtc.org/10629): Move functions that need // internal() to be functions on the SctpTransport interface,
diff --git a/pc/sdp_offer_answer_unittest.cc b/pc/sdp_offer_answer_unittest.cc index c216c89..a4a9c62 100644 --- a/pc/sdp_offer_answer_unittest.cc +++ b/pc/sdp_offer_answer_unittest.cc
@@ -2011,30 +2011,30 @@ auto pc2 = CreatePeerConnection("WebRTC-Sctp-Snap/Disabled/"); EXPECT_TRUE(pc1->pc()->CreateDataChannelOrError("dc", nullptr).ok()); auto offer = pc1->CreateOfferAndSetAsLocal(); - ASSERT_NE(offer, nullptr); + ASSERT_THAT(offer, NotNull()); { auto& contents = offer->description()->contents(); - ASSERT_EQ(contents.size(), 1u); + ASSERT_THAT(contents, SizeIs(1)); auto* media_description = contents[0].media_description(); - ASSERT_TRUE(media_description); + ASSERT_THAT(media_description, NotNull()); auto* sctp_description = media_description->as_sctp(); - ASSERT_TRUE(sctp_description); + ASSERT_THAT(sctp_description, NotNull()); EXPECT_FALSE(sctp_description->sctp_init()); } RTCError error; EXPECT_TRUE(pc2->SetRemoteDescription(std::move(offer))); auto answer = pc2->CreateAnswerAndSetAsLocal(); - ASSERT_NE(answer, nullptr); + ASSERT_THAT(answer, NotNull()); { auto& contents = answer->description()->contents(); - ASSERT_EQ(contents.size(), 1u); + ASSERT_THAT(contents, SizeIs(1)); auto* media_description = contents[0].media_description(); - ASSERT_TRUE(media_description); + ASSERT_THAT(media_description, NotNull()); auto* sctp_description = media_description->as_sctp(); - ASSERT_TRUE(sctp_description); + ASSERT_THAT(sctp_description, NotNull()); EXPECT_FALSE(sctp_description->sctp_init()); } @@ -2046,7 +2046,7 @@ auto pc2 = CreatePeerConnection("WebRTC-Sctp-Snap/Enabled/"); EXPECT_TRUE(pc1->pc()->CreateDataChannelOrError("dc", nullptr).ok()); auto offer = pc1->CreateOfferAndSetAsLocal(); - ASSERT_NE(offer, nullptr); + ASSERT_THAT(offer, NotNull()); { auto& contents = offer->description()->contents(); @@ -2061,7 +2061,7 @@ RTCError error; EXPECT_TRUE(pc2->SetRemoteDescription(std::move(offer))); auto answer = pc2->CreateAnswerAndSetAsLocal(); - ASSERT_NE(answer, nullptr); + ASSERT_THAT(answer, NotNull()); { auto& contents = answer->description()->contents(); @@ -2101,7 +2101,7 @@ EXPECT_TRUE(pc->SetRemoteDescription(std::move(desc))); auto answer = pc->CreateAnswerAndSetAsLocal(); - ASSERT_NE(answer, nullptr); + ASSERT_THAT(answer, NotNull()); EXPECT_TRUE(answer->ToString(&sdp)); auto& contents = answer->description()->contents(); @@ -2134,6 +2134,31 @@ auto desc = CreateSessionDescription(SdpType::kOffer, sdp); EXPECT_EQ(desc, nullptr); } + +TEST_F(SdpOfferAnswerTest, + AnswerFromNewPeerAfterProvisionalAnswerFailsSnapSctpInit) { + auto pc1 = CreatePeerConnection("WebRTC-Sctp-Snap/Enabled/"); + auto pc2 = CreatePeerConnection("WebRTC-Sctp-Snap/Enabled/"); + auto pc3 = CreatePeerConnection("WebRTC-Sctp-Snap/Enabled/"); + EXPECT_TRUE(pc1->pc()->CreateDataChannelOrError("dc", nullptr).ok()); + auto offer = pc1->CreateOfferAndSetAsLocal(); + ASSERT_THAT(offer, NotNull()); + + EXPECT_TRUE(pc2->SetRemoteDescription(offer->Clone())); + EXPECT_TRUE(pc3->SetRemoteDescription(std::move(offer))); + + auto answer2 = pc2->CreateAnswerAndSetAsLocal(); + ASSERT_THAT(answer2, NotNull()); + std::string sdp; + answer2->ToString(&sdp); + auto pranswer2 = CreateSessionDescription(SdpType::kPrAnswer, sdp); + EXPECT_TRUE(pc1->SetRemoteDescription(std::move(pranswer2))); + + // Changing the sctp-init is not supported currently. + auto answer3 = pc3->CreateAnswerAndSetAsLocal(); + ASSERT_THAT(answer3, NotNull()); + EXPECT_FALSE(pc1->SetRemoteDescription(std::move(answer3))); +} #endif // WEBRTC_HAVE_SCTP class SdpOfferAnswerDirectionTest