1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright 2019 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "pc/sctp_transport.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <utility>
14*d9f75844SAndroid Build Coastguard Worker #include <vector>
15*d9f75844SAndroid Build Coastguard Worker
16*d9f75844SAndroid Build Coastguard Worker #include "absl/memory/memory.h"
17*d9f75844SAndroid Build Coastguard Worker #include "absl/types/optional.h"
18*d9f75844SAndroid Build Coastguard Worker #include "api/dtls_transport_interface.h"
19*d9f75844SAndroid Build Coastguard Worker #include "api/transport/data_channel_transport_interface.h"
20*d9f75844SAndroid Build Coastguard Worker #include "media/base/media_channel.h"
21*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/fake_dtls_transport.h"
22*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/p2p_constants.h"
23*d9f75844SAndroid Build Coastguard Worker #include "p2p/base/packet_transport_internal.h"
24*d9f75844SAndroid Build Coastguard Worker #include "pc/dtls_transport.h"
25*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/copy_on_write_buffer.h"
26*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/gunit.h"
27*d9f75844SAndroid Build Coastguard Worker #include "test/gmock.h"
28*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
29*d9f75844SAndroid Build Coastguard Worker
30*d9f75844SAndroid Build Coastguard Worker constexpr int kDefaultTimeout = 1000; // milliseconds
31*d9f75844SAndroid Build Coastguard Worker constexpr int kTestMaxSctpStreams = 1234;
32*d9f75844SAndroid Build Coastguard Worker
33*d9f75844SAndroid Build Coastguard Worker using cricket::FakeDtlsTransport;
34*d9f75844SAndroid Build Coastguard Worker using ::testing::ElementsAre;
35*d9f75844SAndroid Build Coastguard Worker
36*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
37*d9f75844SAndroid Build Coastguard Worker
38*d9f75844SAndroid Build Coastguard Worker namespace {
39*d9f75844SAndroid Build Coastguard Worker
40*d9f75844SAndroid Build Coastguard Worker class FakeCricketSctpTransport : public cricket::SctpTransportInternal {
41*d9f75844SAndroid Build Coastguard Worker public:
SetOnConnectedCallback(std::function<void ()> callback)42*d9f75844SAndroid Build Coastguard Worker void SetOnConnectedCallback(std::function<void()> callback) override {
43*d9f75844SAndroid Build Coastguard Worker on_connected_callback_ = std::move(callback);
44*d9f75844SAndroid Build Coastguard Worker }
SetDataChannelSink(DataChannelSink * sink)45*d9f75844SAndroid Build Coastguard Worker void SetDataChannelSink(DataChannelSink* sink) override {}
SetDtlsTransport(rtc::PacketTransportInternal * transport)46*d9f75844SAndroid Build Coastguard Worker void SetDtlsTransport(rtc::PacketTransportInternal* transport) override {}
Start(int local_port,int remote_port,int max_message_size)47*d9f75844SAndroid Build Coastguard Worker bool Start(int local_port, int remote_port, int max_message_size) override {
48*d9f75844SAndroid Build Coastguard Worker return true;
49*d9f75844SAndroid Build Coastguard Worker }
OpenStream(int sid)50*d9f75844SAndroid Build Coastguard Worker bool OpenStream(int sid) override { return true; }
ResetStream(int sid)51*d9f75844SAndroid Build Coastguard Worker bool ResetStream(int sid) override { return true; }
SendData(int sid,const SendDataParams & params,const rtc::CopyOnWriteBuffer & payload,cricket::SendDataResult * result=nullptr)52*d9f75844SAndroid Build Coastguard Worker bool SendData(int sid,
53*d9f75844SAndroid Build Coastguard Worker const SendDataParams& params,
54*d9f75844SAndroid Build Coastguard Worker const rtc::CopyOnWriteBuffer& payload,
55*d9f75844SAndroid Build Coastguard Worker cricket::SendDataResult* result = nullptr) override {
56*d9f75844SAndroid Build Coastguard Worker return true;
57*d9f75844SAndroid Build Coastguard Worker }
ReadyToSendData()58*d9f75844SAndroid Build Coastguard Worker bool ReadyToSendData() override { return true; }
set_debug_name_for_testing(const char * debug_name)59*d9f75844SAndroid Build Coastguard Worker void set_debug_name_for_testing(const char* debug_name) override {}
max_message_size() const60*d9f75844SAndroid Build Coastguard Worker int max_message_size() const override { return 0; }
max_outbound_streams() const61*d9f75844SAndroid Build Coastguard Worker absl::optional<int> max_outbound_streams() const override {
62*d9f75844SAndroid Build Coastguard Worker return max_outbound_streams_;
63*d9f75844SAndroid Build Coastguard Worker }
max_inbound_streams() const64*d9f75844SAndroid Build Coastguard Worker absl::optional<int> max_inbound_streams() const override {
65*d9f75844SAndroid Build Coastguard Worker return max_inbound_streams_;
66*d9f75844SAndroid Build Coastguard Worker }
67*d9f75844SAndroid Build Coastguard Worker
SendSignalAssociationChangeCommunicationUp()68*d9f75844SAndroid Build Coastguard Worker void SendSignalAssociationChangeCommunicationUp() {
69*d9f75844SAndroid Build Coastguard Worker ASSERT_TRUE(on_connected_callback_);
70*d9f75844SAndroid Build Coastguard Worker on_connected_callback_();
71*d9f75844SAndroid Build Coastguard Worker }
72*d9f75844SAndroid Build Coastguard Worker
set_max_outbound_streams(int streams)73*d9f75844SAndroid Build Coastguard Worker void set_max_outbound_streams(int streams) {
74*d9f75844SAndroid Build Coastguard Worker max_outbound_streams_ = streams;
75*d9f75844SAndroid Build Coastguard Worker }
set_max_inbound_streams(int streams)76*d9f75844SAndroid Build Coastguard Worker void set_max_inbound_streams(int streams) { max_inbound_streams_ = streams; }
77*d9f75844SAndroid Build Coastguard Worker
78*d9f75844SAndroid Build Coastguard Worker private:
79*d9f75844SAndroid Build Coastguard Worker absl::optional<int> max_outbound_streams_;
80*d9f75844SAndroid Build Coastguard Worker absl::optional<int> max_inbound_streams_;
81*d9f75844SAndroid Build Coastguard Worker std::function<void()> on_connected_callback_;
82*d9f75844SAndroid Build Coastguard Worker };
83*d9f75844SAndroid Build Coastguard Worker
84*d9f75844SAndroid Build Coastguard Worker } // namespace
85*d9f75844SAndroid Build Coastguard Worker
86*d9f75844SAndroid Build Coastguard Worker class TestSctpTransportObserver : public SctpTransportObserverInterface {
87*d9f75844SAndroid Build Coastguard Worker public:
TestSctpTransportObserver()88*d9f75844SAndroid Build Coastguard Worker TestSctpTransportObserver() : info_(SctpTransportState::kNew) {}
89*d9f75844SAndroid Build Coastguard Worker
OnStateChange(SctpTransportInformation info)90*d9f75844SAndroid Build Coastguard Worker void OnStateChange(SctpTransportInformation info) override {
91*d9f75844SAndroid Build Coastguard Worker info_ = info;
92*d9f75844SAndroid Build Coastguard Worker states_.push_back(info.state());
93*d9f75844SAndroid Build Coastguard Worker }
94*d9f75844SAndroid Build Coastguard Worker
State()95*d9f75844SAndroid Build Coastguard Worker SctpTransportState State() {
96*d9f75844SAndroid Build Coastguard Worker if (states_.size() > 0) {
97*d9f75844SAndroid Build Coastguard Worker return states_[states_.size() - 1];
98*d9f75844SAndroid Build Coastguard Worker } else {
99*d9f75844SAndroid Build Coastguard Worker return SctpTransportState::kNew;
100*d9f75844SAndroid Build Coastguard Worker }
101*d9f75844SAndroid Build Coastguard Worker }
102*d9f75844SAndroid Build Coastguard Worker
States()103*d9f75844SAndroid Build Coastguard Worker const std::vector<SctpTransportState>& States() { return states_; }
104*d9f75844SAndroid Build Coastguard Worker
LastReceivedInformation()105*d9f75844SAndroid Build Coastguard Worker const SctpTransportInformation LastReceivedInformation() { return info_; }
106*d9f75844SAndroid Build Coastguard Worker
107*d9f75844SAndroid Build Coastguard Worker private:
108*d9f75844SAndroid Build Coastguard Worker std::vector<SctpTransportState> states_;
109*d9f75844SAndroid Build Coastguard Worker SctpTransportInformation info_;
110*d9f75844SAndroid Build Coastguard Worker };
111*d9f75844SAndroid Build Coastguard Worker
112*d9f75844SAndroid Build Coastguard Worker class SctpTransportTest : public ::testing::Test {
113*d9f75844SAndroid Build Coastguard Worker public:
transport()114*d9f75844SAndroid Build Coastguard Worker SctpTransport* transport() { return transport_.get(); }
observer()115*d9f75844SAndroid Build Coastguard Worker SctpTransportObserverInterface* observer() { return &observer_; }
116*d9f75844SAndroid Build Coastguard Worker
CreateTransport()117*d9f75844SAndroid Build Coastguard Worker void CreateTransport() {
118*d9f75844SAndroid Build Coastguard Worker auto cricket_sctp_transport =
119*d9f75844SAndroid Build Coastguard Worker absl::WrapUnique(new FakeCricketSctpTransport());
120*d9f75844SAndroid Build Coastguard Worker transport_ =
121*d9f75844SAndroid Build Coastguard Worker rtc::make_ref_counted<SctpTransport>(std::move(cricket_sctp_transport));
122*d9f75844SAndroid Build Coastguard Worker }
123*d9f75844SAndroid Build Coastguard Worker
AddDtlsTransport()124*d9f75844SAndroid Build Coastguard Worker void AddDtlsTransport() {
125*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<cricket::DtlsTransportInternal> cricket_transport =
126*d9f75844SAndroid Build Coastguard Worker std::make_unique<FakeDtlsTransport>(
127*d9f75844SAndroid Build Coastguard Worker "audio", cricket::ICE_CANDIDATE_COMPONENT_RTP);
128*d9f75844SAndroid Build Coastguard Worker dtls_transport_ =
129*d9f75844SAndroid Build Coastguard Worker rtc::make_ref_counted<DtlsTransport>(std::move(cricket_transport));
130*d9f75844SAndroid Build Coastguard Worker transport_->SetDtlsTransport(dtls_transport_);
131*d9f75844SAndroid Build Coastguard Worker }
132*d9f75844SAndroid Build Coastguard Worker
CompleteSctpHandshake()133*d9f75844SAndroid Build Coastguard Worker void CompleteSctpHandshake() {
134*d9f75844SAndroid Build Coastguard Worker // The computed MaxChannels shall be the minimum of the outgoing
135*d9f75844SAndroid Build Coastguard Worker // and incoming # of streams.
136*d9f75844SAndroid Build Coastguard Worker CricketSctpTransport()->set_max_outbound_streams(kTestMaxSctpStreams);
137*d9f75844SAndroid Build Coastguard Worker CricketSctpTransport()->set_max_inbound_streams(kTestMaxSctpStreams + 1);
138*d9f75844SAndroid Build Coastguard Worker CricketSctpTransport()->SendSignalAssociationChangeCommunicationUp();
139*d9f75844SAndroid Build Coastguard Worker }
140*d9f75844SAndroid Build Coastguard Worker
CricketSctpTransport()141*d9f75844SAndroid Build Coastguard Worker FakeCricketSctpTransport* CricketSctpTransport() {
142*d9f75844SAndroid Build Coastguard Worker return static_cast<FakeCricketSctpTransport*>(transport_->internal());
143*d9f75844SAndroid Build Coastguard Worker }
144*d9f75844SAndroid Build Coastguard Worker
145*d9f75844SAndroid Build Coastguard Worker rtc::AutoThread main_thread_;
146*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<SctpTransport> transport_;
147*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<DtlsTransport> dtls_transport_;
148*d9f75844SAndroid Build Coastguard Worker TestSctpTransportObserver observer_;
149*d9f75844SAndroid Build Coastguard Worker };
150*d9f75844SAndroid Build Coastguard Worker
TEST(SctpTransportSimpleTest,CreateClearDelete)151*d9f75844SAndroid Build Coastguard Worker TEST(SctpTransportSimpleTest, CreateClearDelete) {
152*d9f75844SAndroid Build Coastguard Worker rtc::AutoThread main_thread;
153*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<cricket::SctpTransportInternal> fake_cricket_sctp_transport =
154*d9f75844SAndroid Build Coastguard Worker absl::WrapUnique(new FakeCricketSctpTransport());
155*d9f75844SAndroid Build Coastguard Worker rtc::scoped_refptr<SctpTransport> sctp_transport =
156*d9f75844SAndroid Build Coastguard Worker rtc::make_ref_counted<SctpTransport>(
157*d9f75844SAndroid Build Coastguard Worker std::move(fake_cricket_sctp_transport));
158*d9f75844SAndroid Build Coastguard Worker ASSERT_TRUE(sctp_transport->internal());
159*d9f75844SAndroid Build Coastguard Worker ASSERT_EQ(SctpTransportState::kNew, sctp_transport->Information().state());
160*d9f75844SAndroid Build Coastguard Worker sctp_transport->Clear();
161*d9f75844SAndroid Build Coastguard Worker ASSERT_FALSE(sctp_transport->internal());
162*d9f75844SAndroid Build Coastguard Worker ASSERT_EQ(SctpTransportState::kClosed, sctp_transport->Information().state());
163*d9f75844SAndroid Build Coastguard Worker }
164*d9f75844SAndroid Build Coastguard Worker
TEST_F(SctpTransportTest,EventsObservedWhenConnecting)165*d9f75844SAndroid Build Coastguard Worker TEST_F(SctpTransportTest, EventsObservedWhenConnecting) {
166*d9f75844SAndroid Build Coastguard Worker CreateTransport();
167*d9f75844SAndroid Build Coastguard Worker transport()->RegisterObserver(observer());
168*d9f75844SAndroid Build Coastguard Worker AddDtlsTransport();
169*d9f75844SAndroid Build Coastguard Worker CompleteSctpHandshake();
170*d9f75844SAndroid Build Coastguard Worker ASSERT_EQ_WAIT(SctpTransportState::kConnected, observer_.State(),
171*d9f75844SAndroid Build Coastguard Worker kDefaultTimeout);
172*d9f75844SAndroid Build Coastguard Worker EXPECT_THAT(observer_.States(), ElementsAre(SctpTransportState::kConnecting,
173*d9f75844SAndroid Build Coastguard Worker SctpTransportState::kConnected));
174*d9f75844SAndroid Build Coastguard Worker }
175*d9f75844SAndroid Build Coastguard Worker
TEST_F(SctpTransportTest,CloseWhenClearing)176*d9f75844SAndroid Build Coastguard Worker TEST_F(SctpTransportTest, CloseWhenClearing) {
177*d9f75844SAndroid Build Coastguard Worker CreateTransport();
178*d9f75844SAndroid Build Coastguard Worker transport()->RegisterObserver(observer());
179*d9f75844SAndroid Build Coastguard Worker AddDtlsTransport();
180*d9f75844SAndroid Build Coastguard Worker CompleteSctpHandshake();
181*d9f75844SAndroid Build Coastguard Worker ASSERT_EQ_WAIT(SctpTransportState::kConnected, observer_.State(),
182*d9f75844SAndroid Build Coastguard Worker kDefaultTimeout);
183*d9f75844SAndroid Build Coastguard Worker transport()->Clear();
184*d9f75844SAndroid Build Coastguard Worker ASSERT_EQ_WAIT(SctpTransportState::kClosed, observer_.State(),
185*d9f75844SAndroid Build Coastguard Worker kDefaultTimeout);
186*d9f75844SAndroid Build Coastguard Worker }
187*d9f75844SAndroid Build Coastguard Worker
TEST_F(SctpTransportTest,MaxChannelsSignalled)188*d9f75844SAndroid Build Coastguard Worker TEST_F(SctpTransportTest, MaxChannelsSignalled) {
189*d9f75844SAndroid Build Coastguard Worker CreateTransport();
190*d9f75844SAndroid Build Coastguard Worker transport()->RegisterObserver(observer());
191*d9f75844SAndroid Build Coastguard Worker AddDtlsTransport();
192*d9f75844SAndroid Build Coastguard Worker EXPECT_FALSE(transport()->Information().MaxChannels());
193*d9f75844SAndroid Build Coastguard Worker EXPECT_FALSE(observer_.LastReceivedInformation().MaxChannels());
194*d9f75844SAndroid Build Coastguard Worker CompleteSctpHandshake();
195*d9f75844SAndroid Build Coastguard Worker ASSERT_EQ_WAIT(SctpTransportState::kConnected, observer_.State(),
196*d9f75844SAndroid Build Coastguard Worker kDefaultTimeout);
197*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(transport()->Information().MaxChannels());
198*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(kTestMaxSctpStreams, *(transport()->Information().MaxChannels()));
199*d9f75844SAndroid Build Coastguard Worker EXPECT_TRUE(observer_.LastReceivedInformation().MaxChannels());
200*d9f75844SAndroid Build Coastguard Worker EXPECT_EQ(kTestMaxSctpStreams,
201*d9f75844SAndroid Build Coastguard Worker *(observer_.LastReceivedInformation().MaxChannels()));
202*d9f75844SAndroid Build Coastguard Worker }
203*d9f75844SAndroid Build Coastguard Worker
TEST_F(SctpTransportTest,CloseWhenTransportCloses)204*d9f75844SAndroid Build Coastguard Worker TEST_F(SctpTransportTest, CloseWhenTransportCloses) {
205*d9f75844SAndroid Build Coastguard Worker CreateTransport();
206*d9f75844SAndroid Build Coastguard Worker transport()->RegisterObserver(observer());
207*d9f75844SAndroid Build Coastguard Worker AddDtlsTransport();
208*d9f75844SAndroid Build Coastguard Worker CompleteSctpHandshake();
209*d9f75844SAndroid Build Coastguard Worker ASSERT_EQ_WAIT(SctpTransportState::kConnected, observer_.State(),
210*d9f75844SAndroid Build Coastguard Worker kDefaultTimeout);
211*d9f75844SAndroid Build Coastguard Worker static_cast<cricket::FakeDtlsTransport*>(dtls_transport_->internal())
212*d9f75844SAndroid Build Coastguard Worker ->SetDtlsState(DtlsTransportState::kClosed);
213*d9f75844SAndroid Build Coastguard Worker ASSERT_EQ_WAIT(SctpTransportState::kClosed, observer_.State(),
214*d9f75844SAndroid Build Coastguard Worker kDefaultTimeout);
215*d9f75844SAndroid Build Coastguard Worker }
216*d9f75844SAndroid Build Coastguard Worker
217*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
218