1 /*
2 * Copyright 2022 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "media/sctp/dcsctp_transport.h"
12
13 #include <memory>
14 #include <utility>
15
16 #include "net/dcsctp/public/mock_dcsctp_socket.h"
17 #include "net/dcsctp/public/mock_dcsctp_socket_factory.h"
18 #include "p2p/base/fake_packet_transport.h"
19 #include "test/gtest.h"
20
21 using ::testing::_;
22 using ::testing::ByMove;
23 using ::testing::DoAll;
24 using ::testing::ElementsAre;
25 using ::testing::InSequence;
26 using ::testing::Invoke;
27 using ::testing::NiceMock;
28 using ::testing::Return;
29 using ::testing::ReturnPointee;
30
31 namespace webrtc {
32
33 namespace {
34 class MockDataChannelObserver : public DataChannelSink {
35 public:
36 MOCK_METHOD(void, OnConnected, ());
37
38 // DataChannelSink
39 MOCK_METHOD(void,
40 OnDataReceived,
41 (int, DataMessageType, const rtc::CopyOnWriteBuffer&));
42 MOCK_METHOD(void, OnChannelClosing, (int));
43 MOCK_METHOD(void, OnChannelClosed, (int));
44 MOCK_METHOD(void, OnReadyToSend, ());
45 MOCK_METHOD(void, OnTransportClosed, (RTCError));
46 };
47
48 class Peer {
49 public:
Peer()50 Peer() : fake_packet_transport_("transport"), simulated_clock_(1000) {
51 auto socket_ptr = std::make_unique<dcsctp::MockDcSctpSocket>();
52 socket_ = socket_ptr.get();
53
54 auto mock_dcsctp_socket_factory =
55 std::make_unique<dcsctp::MockDcSctpSocketFactory>();
56 EXPECT_CALL(*mock_dcsctp_socket_factory, Create)
57 .Times(1)
58 .WillOnce(Return(ByMove(std::move(socket_ptr))));
59
60 sctp_transport_ = std::make_unique<webrtc::DcSctpTransport>(
61 rtc::Thread::Current(), &fake_packet_transport_, &simulated_clock_,
62 std::move(mock_dcsctp_socket_factory));
63 sctp_transport_->SetDataChannelSink(&observer_);
64 sctp_transport_->SetOnConnectedCallback(
65 [this]() { observer_.OnConnected(); });
66 }
67
68 rtc::FakePacketTransport fake_packet_transport_;
69 webrtc::SimulatedClock simulated_clock_;
70 dcsctp::MockDcSctpSocket* socket_;
71 std::unique_ptr<webrtc::DcSctpTransport> sctp_transport_;
72 NiceMock<MockDataChannelObserver> observer_;
73 };
74 } // namespace
75
TEST(DcSctpTransportTest,OpenSequence)76 TEST(DcSctpTransportTest, OpenSequence) {
77 rtc::AutoThread main_thread;
78 Peer peer_a;
79 peer_a.fake_packet_transport_.SetWritable(true);
80
81 EXPECT_CALL(*peer_a.socket_, Connect)
82 .Times(1)
83 .WillOnce(Invoke(peer_a.sctp_transport_.get(),
84 &dcsctp::DcSctpSocketCallbacks::OnConnected));
85 EXPECT_CALL(peer_a.observer_, OnReadyToSend);
86 EXPECT_CALL(peer_a.observer_, OnConnected);
87
88 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
89 }
90
91 // Tests that the close sequence invoked from one end results in the stream to
92 // be reset from both ends and all the proper signals are sent.
TEST(DcSctpTransportTest,CloseSequence)93 TEST(DcSctpTransportTest, CloseSequence) {
94 rtc::AutoThread main_thread;
95 Peer peer_a;
96 Peer peer_b;
97 peer_a.fake_packet_transport_.SetDestination(&peer_b.fake_packet_transport_,
98 false);
99 {
100 InSequence sequence;
101
102 EXPECT_CALL(*peer_a.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1))))
103 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed));
104
105 EXPECT_CALL(*peer_b.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1))))
106 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed));
107
108 EXPECT_CALL(peer_a.observer_, OnChannelClosing(1)).Times(0);
109 EXPECT_CALL(peer_b.observer_, OnChannelClosing(1));
110 EXPECT_CALL(peer_a.observer_, OnChannelClosed(1));
111 EXPECT_CALL(peer_b.observer_, OnChannelClosed(1));
112 }
113
114 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
115 peer_b.sctp_transport_->Start(5000, 5000, 256 * 1024);
116 peer_a.sctp_transport_->OpenStream(1);
117 peer_b.sctp_transport_->OpenStream(1);
118 peer_a.sctp_transport_->ResetStream(1);
119
120 // Simulate the callbacks from the stream resets
121 dcsctp::StreamID streams[1] = {dcsctp::StreamID(1)};
122 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
123 ->OnStreamsResetPerformed(streams);
124 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get())
125 ->OnIncomingStreamsReset(streams);
126 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
127 ->OnIncomingStreamsReset(streams);
128 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get())
129 ->OnStreamsResetPerformed(streams);
130 }
131
132 // Tests that the close sequence initiated from both peers at the same time
133 // terminates properly. Both peers will think they initiated it, so no
134 // OnClosingProcedureStartedRemotely should be called.
TEST(DcSctpTransportTest,CloseSequenceSimultaneous)135 TEST(DcSctpTransportTest, CloseSequenceSimultaneous) {
136 rtc::AutoThread main_thread;
137 Peer peer_a;
138 Peer peer_b;
139 peer_a.fake_packet_transport_.SetDestination(&peer_b.fake_packet_transport_,
140 false);
141 {
142 InSequence sequence;
143
144 EXPECT_CALL(*peer_a.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1))))
145 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed));
146
147 EXPECT_CALL(*peer_b.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1))))
148 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed));
149
150 EXPECT_CALL(peer_a.observer_, OnChannelClosing(1)).Times(0);
151 EXPECT_CALL(peer_b.observer_, OnChannelClosing(1)).Times(0);
152 EXPECT_CALL(peer_a.observer_, OnChannelClosed(1));
153 EXPECT_CALL(peer_b.observer_, OnChannelClosed(1));
154 }
155
156 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
157 peer_b.sctp_transport_->Start(5000, 5000, 256 * 1024);
158 peer_a.sctp_transport_->OpenStream(1);
159 peer_b.sctp_transport_->OpenStream(1);
160 peer_a.sctp_transport_->ResetStream(1);
161 peer_b.sctp_transport_->ResetStream(1);
162
163 // Simulate the callbacks from the stream resets
164 dcsctp::StreamID streams[1] = {dcsctp::StreamID(1)};
165 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
166 ->OnStreamsResetPerformed(streams);
167 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get())
168 ->OnStreamsResetPerformed(streams);
169 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
170 ->OnIncomingStreamsReset(streams);
171 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get())
172 ->OnIncomingStreamsReset(streams);
173 }
174
TEST(DcSctpTransportTest,DiscardMessageClosedChannel)175 TEST(DcSctpTransportTest, DiscardMessageClosedChannel) {
176 rtc::AutoThread main_thread;
177 Peer peer_a;
178
179 EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(0);
180
181 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
182
183 cricket::SendDataResult result;
184 SendDataParams params;
185 rtc::CopyOnWriteBuffer payload;
186 bool send_data_return =
187 peer_a.sctp_transport_->SendData(1, params, payload, &result);
188 EXPECT_FALSE(send_data_return);
189 EXPECT_EQ(cricket::SDR_ERROR, result);
190 }
191
TEST(DcSctpTransportTest,DiscardMessageClosingChannel)192 TEST(DcSctpTransportTest, DiscardMessageClosingChannel) {
193 rtc::AutoThread main_thread;
194 Peer peer_a;
195
196 EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(0);
197
198 peer_a.sctp_transport_->OpenStream(1);
199 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
200 peer_a.sctp_transport_->ResetStream(1);
201
202 cricket::SendDataResult result;
203 SendDataParams params;
204 rtc::CopyOnWriteBuffer payload;
205
206 bool send_data_return =
207 peer_a.sctp_transport_->SendData(1, params, payload, &result);
208 EXPECT_FALSE(send_data_return);
209 EXPECT_EQ(cricket::SDR_ERROR, result);
210 }
211
TEST(DcSctpTransportTest,SendDataOpenChannel)212 TEST(DcSctpTransportTest, SendDataOpenChannel) {
213 rtc::AutoThread main_thread;
214 Peer peer_a;
215 dcsctp::DcSctpOptions options;
216
217 EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(1);
218 EXPECT_CALL(*peer_a.socket_, options()).WillOnce(ReturnPointee(&options));
219
220 peer_a.sctp_transport_->OpenStream(1);
221 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
222
223 cricket::SendDataResult result;
224 SendDataParams params;
225 rtc::CopyOnWriteBuffer payload;
226
227 bool send_data_return =
228 peer_a.sctp_transport_->SendData(1, params, payload, &result);
229 EXPECT_TRUE(send_data_return);
230 EXPECT_EQ(cricket::SDR_SUCCESS, result);
231 }
232
233 } // namespace webrtc
234