SCTP: Treat message size zero as "responder selects"
This also refactors some of the code in peerconnection for
handling SCTP transports to be internal to the webrtc::SctpTransport
class, rather than being in peerconnection.
Bug: webrtc:10358, webrtc:10629
Change-Id: I15ecf95c199f56b08909e5a9311d446a412ed162
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/137041
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#27960}
diff --git a/pc/BUILD.gn b/pc/BUILD.gn
index 1013f7c..dd9ca6b 100644
--- a/pc/BUILD.gn
+++ b/pc/BUILD.gn
@@ -295,6 +295,7 @@
"../call:rtp_interfaces",
"../call:rtp_receiver",
"../logging:rtc_event_log_api",
+ "../media:rtc_data",
"../media:rtc_media_base",
"../media:rtc_media_tests_utils",
"../modules/rtp_rtcp:rtp_rtcp_format",
diff --git a/pc/media_session.cc b/pc/media_session.cc
index 0924e6d..1b3d015 100644
--- a/pc/media_session.cc
+++ b/pc/media_session.cc
@@ -2584,8 +2584,15 @@
data_answer->as_sctp()->set_protocol(offer_data_description->protocol());
// Respond with our max message size or the remote max messsage size,
// whichever is smaller.
- data_answer->as_sctp()->set_max_message_size(std::min(
- offer_data_description->max_message_size(), kSctpSendBufferSize));
+ // 0 is treated specially - it means "I can accept any size". Since
+ // we do not implement infinite size messages, reply with
+ // kSctpSendBufferSize.
+ if (offer_data_description->max_message_size() == 0) {
+ data_answer->as_sctp()->set_max_message_size(kSctpSendBufferSize);
+ } else {
+ data_answer->as_sctp()->set_max_message_size(std::min(
+ offer_data_description->max_message_size(), kSctpSendBufferSize));
+ }
if (!CreateMediaContentAnswer(
offer_data_description, media_description_options, session_options,
sdes_policy, GetCryptos(current_content), RtpHeaderExtensions(),
diff --git a/pc/media_session_unittest.cc b/pc/media_session_unittest.cc
index cb90bbc..b14e14c 100644
--- a/pc/media_session_unittest.cc
+++ b/pc/media_session_unittest.cc
@@ -17,6 +17,7 @@
#include "absl/memory/memory.h"
#include "media/base/codec.h"
#include "media/base/test_utils.h"
+#include "media/sctp/sctp_transport_internal.h"
#include "p2p/base/p2p_constants.h"
#include "p2p/base/transport_description.h"
#include "p2p/base/transport_info.h"
@@ -1427,6 +1428,64 @@
}
}
+TEST_F(MediaSessionDescriptionFactoryTest,
+ TestCreateDataAnswerToOfferWithDefinedMessageSize) {
+ // Need to enable DTLS offer/answer generation (disabled by default in this
+ // test).
+ f1_.set_secure(SEC_ENABLED);
+ f2_.set_secure(SEC_ENABLED);
+ tdf1_.set_secure(SEC_ENABLED);
+ tdf2_.set_secure(SEC_ENABLED);
+
+ MediaSessionOptions opts;
+ AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
+ std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
+ ASSERT_TRUE(offer.get() != nullptr);
+ ContentInfo* dc_offer = offer->GetContentByName("data");
+ ASSERT_TRUE(dc_offer != nullptr);
+ SctpDataContentDescription* dcd_offer =
+ dc_offer->media_description()->as_sctp();
+ ASSERT_TRUE(dcd_offer);
+ dcd_offer->set_max_message_size(1234);
+ std::unique_ptr<SessionDescription> answer =
+ f2_.CreateAnswer(offer.get(), opts, nullptr);
+ const ContentInfo* dc_answer = answer->GetContentByName("data");
+ ASSERT_TRUE(dc_answer != nullptr);
+ const SctpDataContentDescription* dcd_answer =
+ dc_answer->media_description()->as_sctp();
+ EXPECT_FALSE(dc_answer->rejected);
+ EXPECT_EQ(1234, dcd_answer->max_message_size());
+}
+
+TEST_F(MediaSessionDescriptionFactoryTest,
+ TestCreateDataAnswerToOfferWithZeroMessageSize) {
+ // Need to enable DTLS offer/answer generation (disabled by default in this
+ // test).
+ f1_.set_secure(SEC_ENABLED);
+ f2_.set_secure(SEC_ENABLED);
+ tdf1_.set_secure(SEC_ENABLED);
+ tdf2_.set_secure(SEC_ENABLED);
+
+ MediaSessionOptions opts;
+ AddDataSection(cricket::DCT_SCTP, RtpTransceiverDirection::kSendRecv, &opts);
+ std::unique_ptr<SessionDescription> offer = f1_.CreateOffer(opts, nullptr);
+ ASSERT_TRUE(offer.get() != nullptr);
+ ContentInfo* dc_offer = offer->GetContentByName("data");
+ ASSERT_TRUE(dc_offer != nullptr);
+ SctpDataContentDescription* dcd_offer =
+ dc_offer->media_description()->as_sctp();
+ ASSERT_TRUE(dcd_offer);
+ dcd_offer->set_max_message_size(0);
+ std::unique_ptr<SessionDescription> answer =
+ f2_.CreateAnswer(offer.get(), opts, nullptr);
+ const ContentInfo* dc_answer = answer->GetContentByName("data");
+ ASSERT_TRUE(dc_answer != nullptr);
+ const SctpDataContentDescription* dcd_answer =
+ dc_answer->media_description()->as_sctp();
+ EXPECT_FALSE(dc_answer->rejected);
+ EXPECT_EQ(cricket::kSctpSendBufferSize, dcd_answer->max_message_size());
+}
+
// Verifies that the order of the media contents in the offer is preserved in
// the answer.
TEST_F(MediaSessionDescriptionFactoryTest, TestCreateAnswerContentOrder) {
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
index e1cc6ef..065247d 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -5657,35 +5657,24 @@
auto remote_sctp_description = cricket::GetFirstSctpDataContentDescription(
remote_description()->description());
if (local_sctp_description && remote_sctp_description) {
- int max_message_size =
- std::min(local_sctp_description->max_message_size(),
- remote_sctp_description->max_message_size());
- bool success = network_thread()->Invoke<bool>(
- RTC_FROM_HERE,
- rtc::Bind(&PeerConnection::PushdownSctpParameters_n, this, source,
- local_sctp_description->port(),
- remote_sctp_description->port(), max_message_size));
- if (!success) {
- LOG_AND_RETURN_ERROR(RTCErrorType::INTERNAL_ERROR,
- "Failed to push down SCTP parameters.");
+ int max_message_size;
+ // A remote max message size of zero means "any size supported".
+ // We configure the connection with our own max message size.
+ if (remote_sctp_description->max_message_size() == 0) {
+ max_message_size = local_sctp_description->max_message_size();
+ } else {
+ max_message_size =
+ std::min(local_sctp_description->max_message_size(),
+ remote_sctp_description->max_message_size());
}
+ sctp_transport_->Start(local_sctp_description->port(),
+ remote_sctp_description->port(), max_message_size);
}
}
return RTCError::OK();
}
-bool PeerConnection::PushdownSctpParameters_n(cricket::ContentSource source,
- int local_sctp_port,
- int remote_sctp_port,
- int max_message_size) {
- RTC_DCHECK_RUN_ON(network_thread());
- // Apply the SCTP port (which is hidden inside a DataCodec structure...)
- // When we support "max-message-size", that would also be pushed down here.
- return cricket_sctp_transport()->Start(local_sctp_port, remote_sctp_port,
- max_message_size);
-}
-
RTCError PeerConnection::PushdownTransportDescription(
cricket::ContentSource source,
SdpType type) {
diff --git a/pc/peer_connection.h b/pc/peer_connection.h
index e83ef1e..3009185 100644
--- a/pc/peer_connection.h
+++ b/pc/peer_connection.h
@@ -877,10 +877,6 @@
// down to all of the channels.
RTCError PushdownMediaDescription(SdpType type, cricket::ContentSource source)
RTC_RUN_ON(signaling_thread());
- bool PushdownSctpParameters_n(cricket::ContentSource source,
- int local_sctp_port,
- int remote_sctp_port,
- int max_message_size);
RTCError PushdownTransportDescription(cricket::ContentSource source,
SdpType type);
diff --git a/pc/sctp_transport.cc b/pc/sctp_transport.cc
index d23d619..1c0289a9 100644
--- a/pc/sctp_transport.cc
+++ b/pc/sctp_transport.cc
@@ -96,6 +96,27 @@
UpdateInformation(next_state);
}
+void SctpTransport::Start(int local_port,
+ int remote_port,
+ int max_message_size) {
+ {
+ rtc::CritScope scope(&lock_);
+ // Record max message size on calling thread.
+ info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(),
+ max_message_size, info_.MaxChannels());
+ }
+ if (owner_thread_->IsCurrent()) {
+ if (!internal()->Start(local_port, remote_port, max_message_size)) {
+ RTC_LOG(LS_ERROR) << "Failed to push down SCTP parameters, closing.";
+ UpdateInformation(SctpTransportState::kClosed);
+ }
+ } else {
+ owner_thread_->Invoke<void>(
+ RTC_FROM_HERE, rtc::Bind(&SctpTransport::Start, this, local_port,
+ remote_port, max_message_size));
+ }
+}
+
void SctpTransport::UpdateInformation(SctpTransportState state) {
RTC_DCHECK_RUN_ON(owner_thread_);
bool must_send_update;
@@ -103,12 +124,11 @@
{
rtc::CritScope scope(&lock_);
must_send_update = (state != info_.state());
- // TODO(https://bugs.webrtc.org/10358): Update max message size and
- // max channels from internal SCTP transport when available.
+ // TODO(https://bugs.webrtc.org/10358): Update max channels from internal
+ // SCTP transport when available.
if (internal_sctp_transport_) {
info_ = SctpTransportInformation(
- state, dtls_transport_, internal_sctp_transport_->max_message_size(),
- info_.MaxChannels());
+ state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
} else {
info_ = SctpTransportInformation(
state, dtls_transport_, info_.MaxMessageSize(), info_.MaxChannels());
diff --git a/pc/sctp_transport.h b/pc/sctp_transport.h
index f1e5092..4a1c6f5 100644
--- a/pc/sctp_transport.h
+++ b/pc/sctp_transport.h
@@ -36,9 +36,16 @@
void RegisterObserver(SctpTransportObserverInterface* observer) override;
void UnregisterObserver() override;
+ // Internal functions
void Clear();
void SetDtlsTransport(rtc::scoped_refptr<DtlsTransport>);
+ // Initialize the cricket::SctpTransport. This can be called from
+ // the signaling thread.
+ void Start(int local_port, int remote_port, int max_message_size);
+ // TODO(https://bugs.webrtc.org/10629): Move functions that need
+ // internal() to be functions on the webrtc::SctpTransport interface,
+ // and make the internal() function private.
cricket::SctpTransportInternal* internal() {
rtc::CritScope scope(&lock_);
return internal_sctp_transport_.get();
@@ -58,7 +65,9 @@
void OnInternalClosingProcedureStartedRemotely(int sid);
void OnInternalClosingProcedureComplete(int sid);
- const rtc::Thread* owner_thread_;
+ // Note - owner_thread never changes, but can't be const if we do
+ // Invoke() on it.
+ rtc::Thread* owner_thread_;
rtc::CriticalSection lock_;
// Variables accessible off-thread, guarded by lock_
SctpTransportInformation info_ RTC_GUARDED_BY(lock_);