Implement max-channels for SCTP datachannels.
This involves catching another callback from usrsctp.
It also moves the definition of "connected" a little later
in the sequence: From "ready to send data" to the reception
of the SCTP_COMM_UP event.
Bug: chromium:943976
Change-Id: Ib9e1b17d0cc356f19cdfa675159b29bf1efdcb55
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/137435
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Steve Anton <steveanton@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28004}
diff --git a/media/sctp/sctp_transport.cc b/media/sctp/sctp_transport.cc
index 0858401..7c60832 100644
--- a/media/sctp/sctp_transport.cc
+++ b/media/sctp/sctp_transport.cc
@@ -1047,7 +1047,12 @@
RTC_DCHECK_RUN_ON(network_thread_);
switch (change.sac_state) {
case SCTP_COMM_UP:
- RTC_LOG(LS_VERBOSE) << "Association change SCTP_COMM_UP";
+ RTC_LOG(LS_VERBOSE) << "Association change SCTP_COMM_UP, stream # is "
+ << change.sac_outbound_streams << " outbound, "
+ << change.sac_inbound_streams << " inbound.";
+ max_outbound_streams_ = change.sac_outbound_streams;
+ max_inbound_streams_ = change.sac_inbound_streams;
+ SignalAssociationChangeCommunicationUp();
break;
case SCTP_COMM_LOST:
RTC_LOG(LS_INFO) << "Association change SCTP_COMM_LOST";
diff --git a/media/sctp/sctp_transport.h b/media/sctp/sctp_transport.h
index 554407b..297379b 100644
--- a/media/sctp/sctp_transport.h
+++ b/media/sctp/sctp_transport.h
@@ -80,6 +80,12 @@
SendDataResult* result = nullptr) override;
bool ReadyToSendData() override;
int max_message_size() const override { return max_message_size_; }
+ absl::optional<int> max_outbound_streams() const override {
+ return max_outbound_streams_;
+ }
+ absl::optional<int> max_inbound_streams() const override {
+ return max_inbound_streams_;
+ }
void set_debug_name_for_testing(const char* debug_name) override {
debug_name_ = debug_name;
}
@@ -208,6 +214,9 @@
const char* debug_name_ = "SctpTransport";
// Hides usrsctp interactions from this header file.
class UsrSctpWrapper;
+ // Number of channels negotiated. Not set before negotiation completes.
+ absl::optional<int> max_outbound_streams_;
+ absl::optional<int> max_inbound_streams_;
RTC_DISALLOW_COPY_AND_ASSIGN(SctpTransport);
};
diff --git a/media/sctp/sctp_transport_internal.h b/media/sctp/sctp_transport_internal.h
index c08c414..378453a 100644
--- a/media/sctp/sctp_transport_internal.h
+++ b/media/sctp/sctp_transport_internal.h
@@ -114,8 +114,14 @@
virtual bool ReadyToSendData() = 0;
// Returns the current max message size, set with Start().
virtual int max_message_size() const = 0;
+ // Returns the current negotiated max # of outbound streams.
+ // Will return absl::nullopt if negotiation is incomplete.
+ virtual absl::optional<int> max_outbound_streams() const = 0;
+ // Returns the current negotiated max # of inbound streams.
+ virtual absl::optional<int> max_inbound_streams() const = 0;
sigslot::signal0<> SignalReadyToSendData;
+ sigslot::signal0<> SignalAssociationChangeCommunicationUp;
// ReceiveDataParams includes SID, seq num, timestamp, etc. CopyOnWriteBuffer
// contains message payload.
sigslot::signal2<const ReceiveDataParams&, const rtc::CopyOnWriteBuffer&>
diff --git a/pc/sctp_transport.cc b/pc/sctp_transport.cc
index 1c0289a9..6c4a8be 100644
--- a/pc/sctp_transport.cc
+++ b/pc/sctp_transport.cc
@@ -10,6 +10,7 @@
#include "pc/sctp_transport.h"
+#include <algorithm>
#include <utility>
namespace webrtc {
@@ -20,8 +21,8 @@
info_(SctpTransportState::kNew),
internal_sctp_transport_(std::move(internal)) {
RTC_DCHECK(internal_sctp_transport_.get());
- internal_sctp_transport_->SignalReadyToSendData.connect(
- this, &SctpTransport::OnInternalReadyToSendData);
+ internal_sctp_transport_->SignalAssociationChangeCommunicationUp.connect(
+ this, &SctpTransport::OnAssociationChangeCommunicationUp);
// TODO(https://bugs.webrtc.org/10360): Add handlers for transport closing.
if (dtls_transport_) {
@@ -143,7 +144,21 @@
}
}
-void SctpTransport::OnInternalReadyToSendData() {
+void SctpTransport::OnAssociationChangeCommunicationUp() {
+ RTC_DCHECK_RUN_ON(owner_thread_);
+ {
+ rtc::CritScope scope(&lock_);
+ RTC_DCHECK(internal_sctp_transport_);
+ if (internal_sctp_transport_->max_outbound_streams() &&
+ internal_sctp_transport_->max_inbound_streams()) {
+ int max_channels =
+ std::min(*(internal_sctp_transport_->max_outbound_streams()),
+ *(internal_sctp_transport_->max_inbound_streams()));
+ // Record max channels.
+ info_ = SctpTransportInformation(info_.state(), info_.dtls_transport(),
+ info_.MaxMessageSize(), max_channels);
+ }
+ }
UpdateInformation(SctpTransportState::kConnected);
}
diff --git a/pc/sctp_transport.h b/pc/sctp_transport.h
index 4a1c6f5..c7727df 100644
--- a/pc/sctp_transport.h
+++ b/pc/sctp_transport.h
@@ -62,6 +62,7 @@
private:
void UpdateInformation(SctpTransportState state);
void OnInternalReadyToSendData();
+ void OnAssociationChangeCommunicationUp();
void OnInternalClosingProcedureStartedRemotely(int sid);
void OnInternalClosingProcedureComplete(int sid);
diff --git a/pc/sctp_transport_unittest.cc b/pc/sctp_transport_unittest.cc
index 3438b17..ca57d6a 100644
--- a/pc/sctp_transport_unittest.cc
+++ b/pc/sctp_transport_unittest.cc
@@ -21,6 +21,7 @@
#include "test/gtest.h"
constexpr int kDefaultTimeout = 1000; // milliseconds
+constexpr int kTestMaxSctpStreams = 1234;
using cricket::FakeDtlsTransport;
using ::testing::ElementsAre;
@@ -45,9 +46,19 @@
bool ReadyToSendData() override { return true; }
void set_debug_name_for_testing(const char* debug_name) override {}
int max_message_size() const override { return 0; }
+ absl::optional<int> max_outbound_streams() const override {
+ return max_outbound_streams_;
+ }
+ absl::optional<int> max_inbound_streams() const override {
+ return max_inbound_streams_;
+ }
// Methods exposed for testing
void SendSignalReadyToSendData() { SignalReadyToSendData(); }
+ void SendSignalAssociationChangeCommunicationUp() {
+ SignalAssociationChangeCommunicationUp();
+ }
+
void SendSignalClosingProcedureStartedRemotely() {
SignalClosingProcedureStartedRemotely(1);
}
@@ -55,13 +66,24 @@
void SendSignalClosingProcedureComplete() {
SignalClosingProcedureComplete(1);
}
+ void set_max_outbound_streams(int streams) {
+ max_outbound_streams_ = streams;
+ }
+ void set_max_inbound_streams(int streams) { max_inbound_streams_ = streams; }
+
+ private:
+ absl::optional<int> max_outbound_streams_;
+ absl::optional<int> max_inbound_streams_;
};
} // namespace
class TestSctpTransportObserver : public SctpTransportObserverInterface {
public:
+ TestSctpTransportObserver() : info_(SctpTransportState::kNew) {}
+
void OnStateChange(SctpTransportInformation info) override {
+ info_ = info;
states_.push_back(info.state());
}
@@ -75,8 +97,11 @@
const std::vector<SctpTransportState>& States() { return states_; }
+ const SctpTransportInformation LastReceivedInformation() { return info_; }
+
private:
std::vector<SctpTransportState> states_;
+ SctpTransportInformation info_;
};
class SctpTransportTest : public ::testing::Test {
@@ -102,6 +127,11 @@
void CompleteSctpHandshake() {
CricketSctpTransport()->SendSignalReadyToSendData();
+ // The computed MaxChannels shall be the minimum of the outgoing
+ // and incoming # of streams.
+ CricketSctpTransport()->set_max_outbound_streams(kTestMaxSctpStreams);
+ CricketSctpTransport()->set_max_inbound_streams(kTestMaxSctpStreams + 1);
+ CricketSctpTransport()->SendSignalAssociationChangeCommunicationUp();
}
FakeCricketSctpTransport* CricketSctpTransport() {
@@ -149,4 +179,20 @@
kDefaultTimeout);
}
+TEST_F(SctpTransportTest, MaxChannelsSignalled) {
+ CreateTransport();
+ transport()->RegisterObserver(observer());
+ AddDtlsTransport();
+ EXPECT_FALSE(transport()->Information().MaxChannels());
+ EXPECT_FALSE(observer_.LastReceivedInformation().MaxChannels());
+ CompleteSctpHandshake();
+ ASSERT_EQ_WAIT(SctpTransportState::kConnected, observer_.State(),
+ kDefaultTimeout);
+ EXPECT_TRUE(transport()->Information().MaxChannels());
+ EXPECT_EQ(kTestMaxSctpStreams, *(transport()->Information().MaxChannels()));
+ EXPECT_TRUE(observer_.LastReceivedInformation().MaxChannels());
+ EXPECT_EQ(kTestMaxSctpStreams,
+ *(observer_.LastReceivedInformation().MaxChannels()));
+}
+
} // namespace webrtc
diff --git a/pc/test/fake_sctp_transport.h b/pc/test/fake_sctp_transport.h
index b3eeee0..50e59f1 100644
--- a/pc/test/fake_sctp_transport.h
+++ b/pc/test/fake_sctp_transport.h
@@ -38,6 +38,8 @@
void set_debug_name_for_testing(const char* debug_name) override {}
int max_message_size() const { return max_message_size_; }
+ absl::optional<int> max_outbound_streams() const { return absl::nullopt; }
+ absl::optional<int> max_inbound_streams() const { return absl::nullopt; }
int local_port() const { return *local_port_; }
int remote_port() const { return *remote_port_; }