blob: 65fc3a1690c8669f18a5e81599218025d2b4ce6d [file] [log] [blame]
Florent Castellie3b74f82022-05-02 22:24:151/*
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
Florent Castellidbc2ba22022-08-22 17:46:3921using ::testing::_;
Florent Castellie3b74f82022-05-02 22:24:1522using ::testing::ByMove;
23using ::testing::DoAll;
24using ::testing::ElementsAre;
25using ::testing::InSequence;
26using ::testing::Invoke;
27using ::testing::NiceMock;
28using ::testing::Return;
Florent Castellidbc2ba22022-08-22 17:46:3929using ::testing::ReturnPointee;
Florent Castellie3b74f82022-05-02 22:24:1530
31namespace webrtc {
32
33namespace {
Florent Castelli691d4a02023-03-13 14:17:1734class MockDataChannelSink : public DataChannelSink {
Florent Castellie3b74f82022-05-02 22:24:1535 public:
Fredrik Solenberg5cb3a902022-08-22 09:34:2936 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));
Florent Castellie3b74f82022-05-02 22:24:1546};
47
Florent Castelli691d4a02023-03-13 14:17:1748static_assert(!std::is_abstract_v<MockDataChannelSink>);
49
Florent Castellie3b74f82022-05-02 22:24:1550class Peer {
51 public:
52 Peer() : fake_packet_transport_("transport"), simulated_clock_(1000) {
53 auto socket_ptr = std::make_unique<dcsctp::MockDcSctpSocket>();
54 socket_ = socket_ptr.get();
55
56 auto mock_dcsctp_socket_factory =
57 std::make_unique<dcsctp::MockDcSctpSocketFactory>();
58 EXPECT_CALL(*mock_dcsctp_socket_factory, Create)
59 .Times(1)
60 .WillOnce(Return(ByMove(std::move(socket_ptr))));
61
62 sctp_transport_ = std::make_unique<webrtc::DcSctpTransport>(
63 rtc::Thread::Current(), &fake_packet_transport_, &simulated_clock_,
64 std::move(mock_dcsctp_socket_factory));
Florent Castelli691d4a02023-03-13 14:17:1765 sctp_transport_->SetDataChannelSink(&sink_);
66 sctp_transport_->SetOnConnectedCallback([this]() { sink_.OnConnected(); });
Florent Castellie3b74f82022-05-02 22:24:1567 }
68
69 rtc::FakePacketTransport fake_packet_transport_;
70 webrtc::SimulatedClock simulated_clock_;
71 dcsctp::MockDcSctpSocket* socket_;
72 std::unique_ptr<webrtc::DcSctpTransport> sctp_transport_;
Florent Castelli691d4a02023-03-13 14:17:1773 NiceMock<MockDataChannelSink> sink_;
Florent Castellie3b74f82022-05-02 22:24:1574};
75} // namespace
76
77TEST(DcSctpTransportTest, OpenSequence) {
Niels Möller83830f32022-05-20 07:12:5778 rtc::AutoThread main_thread;
Florent Castellie3b74f82022-05-02 22:24:1579 Peer peer_a;
80 peer_a.fake_packet_transport_.SetWritable(true);
81
82 EXPECT_CALL(*peer_a.socket_, Connect)
83 .Times(1)
84 .WillOnce(Invoke(peer_a.sctp_transport_.get(),
85 &dcsctp::DcSctpSocketCallbacks::OnConnected));
Florent Castelli691d4a02023-03-13 14:17:1786 EXPECT_CALL(peer_a.sink_, OnReadyToSend);
87 EXPECT_CALL(peer_a.sink_, OnConnected);
Florent Castellie3b74f82022-05-02 22:24:1588
89 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
90}
91
Florent Castelli8f04c7c2022-05-05 21:43:4492// Tests that the close sequence invoked from one end results in the stream to
93// be reset from both ends and all the proper signals are sent.
Florent Castellie3b74f82022-05-02 22:24:1594TEST(DcSctpTransportTest, CloseSequence) {
Niels Möller83830f32022-05-20 07:12:5795 rtc::AutoThread main_thread;
Florent Castellie3b74f82022-05-02 22:24:1596 Peer peer_a;
97 Peer peer_b;
98 peer_a.fake_packet_transport_.SetDestination(&peer_b.fake_packet_transport_,
99 false);
100 {
101 InSequence sequence;
102
103 EXPECT_CALL(*peer_a.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1))))
Florent Castelli8f04c7c2022-05-05 21:43:44104 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed));
Florent Castellie3b74f82022-05-02 22:24:15105
106 EXPECT_CALL(*peer_b.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1))))
Florent Castelli8f04c7c2022-05-05 21:43:44107 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed));
Florent Castellie3b74f82022-05-02 22:24:15108
Florent Castelli691d4a02023-03-13 14:17:17109 EXPECT_CALL(peer_a.sink_, OnChannelClosing(1)).Times(0);
110 EXPECT_CALL(peer_b.sink_, OnChannelClosing(1));
111 EXPECT_CALL(peer_a.sink_, OnChannelClosed(1));
112 EXPECT_CALL(peer_b.sink_, OnChannelClosed(1));
Florent Castellie3b74f82022-05-02 22:24:15113 }
114
115 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
116 peer_b.sctp_transport_->Start(5000, 5000, 256 * 1024);
117 peer_a.sctp_transport_->OpenStream(1);
Florent Castellidbc2ba22022-08-22 17:46:39118 peer_b.sctp_transport_->OpenStream(1);
Florent Castellie3b74f82022-05-02 22:24:15119 peer_a.sctp_transport_->ResetStream(1);
Florent Castelli8f04c7c2022-05-05 21:43:44120
121 // Simulate the callbacks from the stream resets
122 dcsctp::StreamID streams[1] = {dcsctp::StreamID(1)};
123 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
124 ->OnStreamsResetPerformed(streams);
125 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get())
126 ->OnIncomingStreamsReset(streams);
127 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
128 ->OnIncomingStreamsReset(streams);
129 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get())
130 ->OnStreamsResetPerformed(streams);
131}
132
133// Tests that the close sequence initiated from both peers at the same time
134// terminates properly. Both peers will think they initiated it, so no
Fredrik Solenberg5cb3a902022-08-22 09:34:29135// OnClosingProcedureStartedRemotely should be called.
Florent Castelli8f04c7c2022-05-05 21:43:44136TEST(DcSctpTransportTest, CloseSequenceSimultaneous) {
Niels Möller83830f32022-05-20 07:12:57137 rtc::AutoThread main_thread;
Florent Castelli8f04c7c2022-05-05 21:43:44138 Peer peer_a;
139 Peer peer_b;
140 peer_a.fake_packet_transport_.SetDestination(&peer_b.fake_packet_transport_,
141 false);
142 {
143 InSequence sequence;
144
145 EXPECT_CALL(*peer_a.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1))))
146 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed));
147
148 EXPECT_CALL(*peer_b.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1))))
149 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed));
150
Florent Castelli691d4a02023-03-13 14:17:17151 EXPECT_CALL(peer_a.sink_, OnChannelClosing(1)).Times(0);
152 EXPECT_CALL(peer_b.sink_, OnChannelClosing(1)).Times(0);
153 EXPECT_CALL(peer_a.sink_, OnChannelClosed(1));
154 EXPECT_CALL(peer_b.sink_, OnChannelClosed(1));
Florent Castelli8f04c7c2022-05-05 21:43:44155 }
156
157 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
158 peer_b.sctp_transport_->Start(5000, 5000, 256 * 1024);
159 peer_a.sctp_transport_->OpenStream(1);
Florent Castellidbc2ba22022-08-22 17:46:39160 peer_b.sctp_transport_->OpenStream(1);
Florent Castelli8f04c7c2022-05-05 21:43:44161 peer_a.sctp_transport_->ResetStream(1);
162 peer_b.sctp_transport_->ResetStream(1);
163
164 // Simulate the callbacks from the stream resets
165 dcsctp::StreamID streams[1] = {dcsctp::StreamID(1)};
166 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
167 ->OnStreamsResetPerformed(streams);
168 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get())
169 ->OnStreamsResetPerformed(streams);
170 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
171 ->OnIncomingStreamsReset(streams);
172 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get())
173 ->OnIncomingStreamsReset(streams);
Florent Castellie3b74f82022-05-02 22:24:15174}
175
Florent Castellidbc2ba22022-08-22 17:46:39176TEST(DcSctpTransportTest, DiscardMessageClosedChannel) {
177 rtc::AutoThread main_thread;
178 Peer peer_a;
179
180 EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(0);
181
182 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
183
Florent Castellidbc2ba22022-08-22 17:46:39184 SendDataParams params;
185 rtc::CopyOnWriteBuffer payload;
Tommi1fabbac2023-03-21 13:48:51186 EXPECT_EQ(peer_a.sctp_transport_->SendData(1, params, payload).type(),
187 RTCErrorType::INVALID_STATE);
Florent Castellidbc2ba22022-08-22 17:46:39188}
189
190TEST(DcSctpTransportTest, DiscardMessageClosingChannel) {
191 rtc::AutoThread main_thread;
192 Peer peer_a;
193
194 EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(0);
195
196 peer_a.sctp_transport_->OpenStream(1);
197 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
198 peer_a.sctp_transport_->ResetStream(1);
199
Florent Castellidbc2ba22022-08-22 17:46:39200 SendDataParams params;
201 rtc::CopyOnWriteBuffer payload;
Tommi1fabbac2023-03-21 13:48:51202 EXPECT_EQ(peer_a.sctp_transport_->SendData(1, params, payload).type(),
203 RTCErrorType::INVALID_STATE);
Florent Castellidbc2ba22022-08-22 17:46:39204}
205
206TEST(DcSctpTransportTest, SendDataOpenChannel) {
207 rtc::AutoThread main_thread;
208 Peer peer_a;
209 dcsctp::DcSctpOptions options;
210
211 EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(1);
212 EXPECT_CALL(*peer_a.socket_, options()).WillOnce(ReturnPointee(&options));
213
214 peer_a.sctp_transport_->OpenStream(1);
215 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
216
Florent Castellidbc2ba22022-08-22 17:46:39217 SendDataParams params;
218 rtc::CopyOnWriteBuffer payload;
Tommi1fabbac2023-03-21 13:48:51219 EXPECT_TRUE(peer_a.sctp_transport_->SendData(1, params, payload).ok());
Florent Castellidbc2ba22022-08-22 17:46:39220}
221
Florent Castelli691d4a02023-03-13 14:17:17222TEST(DcSctpTransportTest, DeliversMessage) {
223 rtc::AutoThread main_thread;
224 Peer peer_a;
225
226 EXPECT_CALL(peer_a.sink_,
227 OnDataReceived(1, webrtc::DataMessageType::kBinary, _))
228 .Times(1);
229
230 peer_a.sctp_transport_->OpenStream(1);
231 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
232
233 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
234 ->OnMessageReceived(
235 dcsctp::DcSctpMessage(dcsctp::StreamID(1), dcsctp::PPID(53), {0}));
236}
237
238TEST(DcSctpTransportTest, DropMessageWithUnknownPpid) {
239 rtc::AutoThread main_thread;
240 Peer peer_a;
241
242 EXPECT_CALL(peer_a.sink_, OnDataReceived(_, _, _)).Times(0);
243
244 peer_a.sctp_transport_->OpenStream(1);
245 peer_a.sctp_transport_->Start(5000, 5000, 256 * 1024);
246
247 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get())
248 ->OnMessageReceived(
249 dcsctp::DcSctpMessage(dcsctp::StreamID(1), dcsctp::PPID(1337), {0}));
250}
Florent Castellie3b74f82022-05-02 22:24:15251} // namespace webrtc