/*
* Copyright 2019 The WebRTC project authors . All Rights Reserved .
*
* Use of this source code is governed by a BSD - style license
* that can be found in the LICENSE file in the root of the source
* tree . An additional intellectual property rights grant can be found
* in the file PATENTS . All contributing project authors may
* be found in the AUTHORS file in the root of the source tree .
*/
#include "pc/sctp_transport.h"
#include <cstddef>
#include <functional>
#include <memory>
#include <optional>
#include <utility>
#include <vector>
#include "absl/memory/memory.h"
#include "api/dtls_transport_interface.h"
#include "api/make_ref_counted.h"
#include "api/priority.h"
#include "api/rtc_error.h"
#include "api/scoped_refptr.h"
#include "api/sctp_transport_interface.h"
#include "api/test/rtc_error_matchers.h"
#include "api/transport/data_channel_transport_interface.h"
#include "media/sctp/sctp_transport_internal.h"
#include "p2p/base/p2p_constants.h"
#include "p2p/dtls/dtls_transport_internal.h"
#include "p2p/dtls/fake_dtls_transport.h"
#include "pc/dtls_transport.h"
#include "rtc_base/copy_on_write_buffer.h"
#include "test/gmock.h"
#include "test/gtest.h"
#include "test/run_loop.h"
#include "test/wait_until.h"
namespace webrtc {
constexpr int kTestMaxSctpStreams = 1234 ;
using ::testing::ElementsAre;
namespace {
class FakeSctpTransportInternal : public SctpTransportInternal {
public :
explicit FakeSctpTransportInternal(DtlsTransportInternal* transport)
: transport_(transport) {}
void SetOnConnectedCallback(std::function<void ()> callback) override {
on_connected_callback_ = std::move(callback);
}
void SetDataChannelSink(DataChannelSink* sink) override {}
DtlsTransportInternal* dtls_transport() const override { return transport_; }
bool Start(const SctpOptions& options) override { return true ; }
bool OpenStream(int sid, PriorityValue priority) override { return true ; }
bool ResetStream(int sid) override { return true ; }
RTCError SendData(int sid,
const SendDataParams& params,
const CopyOnWriteBuffer& payload) override {
return RTCError::OK();
}
bool ReadyToSendData() override { return true ; }
int max_message_size() const override { return 0 ; }
std::optional<int> max_outbound_streams() const override {
return max_outbound_streams_;
}
std::optional<int> max_inbound_streams() const override {
return max_inbound_streams_;
}
size_t buffered_amount(int sid) const override { return 0 ; }
size_t buffered_amount_low_threshold(int sid) const override { return 0 ; }
void SetBufferedAmountLowThreshold(int sid, size_t bytes) override {}
void SendSignalAssociationChangeCommunicationUp() {
ASSERT_TRUE(on_connected_callback_);
on_connected_callback_();
}
void set_max_outbound_streams(int streams) {
max_outbound_streams_ = streams;
}
void set_max_inbound_streams(int streams) { max_inbound_streams_ = streams; }
private :
DtlsTransportInternal* const transport_;
std::optional<int> max_outbound_streams_;
std::optional<int> max_inbound_streams_;
std::function<void ()> on_connected_callback_;
};
} // namespace
class TestSctpTransportObserver : public SctpTransportObserverInterface {
public :
TestSctpTransportObserver() : info_(SctpTransportState::kNew) {}
void OnStateChange(SctpTransportInformation info) override {
info_ = info;
states_.push_back(info.state());
}
SctpTransportState State() {
if (!states_.empty()) {
return states_[states_.size() - 1 ];
} else {
return SctpTransportState::kNew;
}
}
const std::vector<SctpTransportState>& States() { return states_; }
SctpTransportInformation LastReceivedInformation() { return info_; }
private :
std::vector<SctpTransportState> states_;
SctpTransportInformation info_;
};
class SctpTransportTest : public ::testing::Test {
public :
SctpTransport* transport() { return transport_.get(); }
SctpTransportObserverInterface* observer() { return &observer_; }
void TearDown() override {
if (dtls_transport_ && internal_transport_) {
internal_transport_->UnsubscribeDtlsTransportState(dtls_transport_.get());
dtls_transport_->Clear(internal_transport_.get());
}
}
void CreateTransport() {
internal_transport_ = std::make_unique<FakeDtlsTransport>(
"audio" , ICE_CANDIDATE_COMPONENT_RTP);
dtls_transport_ =
make_ref_counted<DtlsTransport>(internal_transport_.get());
internal_transport_->SubscribeDtlsTransportState(
dtls_transport_.get(),
[this ](DtlsTransportInternal* transport, DtlsTransportState state) {
dtls_transport_->OnInternalDtlsState(transport);
});
auto sctp_transport_internal = absl::WrapUnique(
new FakeSctpTransportInternal(internal_transport_.get()));
transport_ = make_ref_counted<SctpTransport>(
std::move(sctp_transport_internal), dtls_transport_);
}
void CompleteSctpHandshake() {
// The computed MaxChannels shall be the minimum of the outgoing
// and incoming # of streams.
MySctpTransportInternal()->set_max_outbound_streams(kTestMaxSctpStreams);
MySctpTransportInternal()->set_max_inbound_streams(kTestMaxSctpStreams + 1 );
MySctpTransportInternal()->SendSignalAssociationChangeCommunicationUp();
}
FakeSctpTransportInternal* MySctpTransportInternal() {
return static_cast <FakeSctpTransportInternal*>(transport_->internal());
}
test::RunLoop main_thread_;
scoped_refptr<SctpTransport> transport_;
scoped_refptr<DtlsTransport> dtls_transport_;
std::unique_ptr<FakeDtlsTransport> internal_transport_;
TestSctpTransportObserver observer_;
};
TEST(SctpTransportSimpleTest, CreateClearDelete) {
test::RunLoop main_thread;
std::unique_ptr<DtlsTransportInternal> internal_transport =
std::make_unique<FakeDtlsTransport>("audio" , ICE_CANDIDATE_COMPONENT_RTP);
scoped_refptr<DtlsTransport> dtls_transport =
make_ref_counted<DtlsTransport>(internal_transport.get());
std::unique_ptr<SctpTransportInternal> fake_sctp_transport_internal =
absl::WrapUnique(new FakeSctpTransportInternal(internal_transport.get()));
scoped_refptr<SctpTransport> sctp_transport = make_ref_counted<SctpTransport>(
std::move(fake_sctp_transport_internal), dtls_transport);
ASSERT_TRUE(sctp_transport->internal());
ASSERT_EQ(SctpTransportState::kConnecting,
sctp_transport->Information().state());
sctp_transport->Clear();
ASSERT_FALSE(sctp_transport->internal());
ASSERT_EQ(SctpTransportState::kClosed, sctp_transport->Information().state());
dtls_transport->Clear(internal_transport.get());
}
TEST_F(SctpTransportTest, EventsObservedWhenConnecting) {
CreateTransport();
transport()->RegisterObserver(observer());
CompleteSctpHandshake();
ASSERT_THAT(WaitUntil([&] { return observer_.State(); },
::testing::Eq(SctpTransportState::kConnected)),
IsRtcOk());
EXPECT_THAT(observer_.States(), ElementsAre(SctpTransportState::kConnected));
}
TEST_F(SctpTransportTest, CloseWhenClearing) {
CreateTransport();
transport()->RegisterObserver(observer());
CompleteSctpHandshake();
ASSERT_THAT(WaitUntil([&] { return observer_.State(); },
::testing::Eq(SctpTransportState::kConnected)),
IsRtcOk());
transport()->Clear();
ASSERT_THAT(WaitUntil([&] { return observer_.State(); },
::testing::Eq(SctpTransportState::kClosed)),
IsRtcOk());
}
TEST_F(SctpTransportTest, MaxChannelsSignalled) {
CreateTransport();
transport()->RegisterObserver(observer());
EXPECT_FALSE(transport()->Information().MaxChannels());
EXPECT_FALSE(observer_.LastReceivedInformation().MaxChannels());
CompleteSctpHandshake();
ASSERT_THAT(WaitUntil([&] { return observer_.State(); },
::testing::Eq(SctpTransportState::kConnected)),
IsRtcOk());
EXPECT_TRUE(transport()->Information().MaxChannels());
EXPECT_EQ(kTestMaxSctpStreams, *(transport()->Information().MaxChannels()));
EXPECT_TRUE(observer_.LastReceivedInformation().MaxChannels());
EXPECT_EQ(kTestMaxSctpStreams,
*(observer_.LastReceivedInformation().MaxChannels()));
}
TEST_F(SctpTransportTest, CloseWhenTransportCloses) {
CreateTransport();
transport()->RegisterObserver(observer());
CompleteSctpHandshake();
ASSERT_THAT(WaitUntil([&] { return observer_.State(); },
::testing::Eq(SctpTransportState::kConnected)),
IsRtcOk());
internal_transport_->SetDtlsState(DtlsTransportState::kClosed);
ASSERT_THAT(WaitUntil([&] { return observer_.State(); },
::testing::Eq(SctpTransportState::kClosed)),
IsRtcOk());
}
} // namespace webrtc
Messung V0.5 in Prozent C=98 H=100 G=98
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-08-27)
¤
*© Formatika GbR, Deutschland