dcsctp_transport_unittest.cc (11721B)
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 <type_traits> 15 #include <utility> 16 17 #include "api/environment/environment.h" 18 #include "api/environment/environment_factory.h" 19 #include "api/priority.h" 20 #include "api/rtc_error.h" 21 #include "api/transport/data_channel_transport_interface.h" 22 #include "net/dcsctp/public/dcsctp_message.h" 23 #include "net/dcsctp/public/dcsctp_options.h" 24 #include "net/dcsctp/public/dcsctp_socket.h" 25 #include "net/dcsctp/public/mock_dcsctp_socket.h" 26 #include "net/dcsctp/public/mock_dcsctp_socket_factory.h" 27 #include "net/dcsctp/public/types.h" 28 #include "p2p/dtls/fake_dtls_transport.h" 29 #include "rtc_base/copy_on_write_buffer.h" 30 #include "rtc_base/thread.h" 31 #include "system_wrappers/include/clock.h" 32 #include "test/gmock.h" 33 #include "test/gtest.h" 34 35 using ::testing::_; 36 using ::testing::ByMove; 37 using ::testing::ElementsAre; 38 using ::testing::InSequence; 39 using ::testing::Invoke; 40 using ::testing::NiceMock; 41 using ::testing::Return; 42 using ::testing::ReturnPointee; 43 44 namespace webrtc { 45 46 namespace { 47 48 constexpr char kTransportName[] = "transport"; 49 constexpr int kComponent = 77; 50 51 const PriorityValue kDefaultPriority = PriorityValue(Priority::kLow); 52 53 class MockDataChannelSink : public DataChannelSink { 54 public: 55 MOCK_METHOD(void, OnConnected, ()); 56 57 // DataChannelSink 58 MOCK_METHOD(void, 59 OnDataReceived, 60 (int, DataMessageType, const CopyOnWriteBuffer&)); 61 MOCK_METHOD(void, OnChannelClosing, (int)); 62 MOCK_METHOD(void, OnChannelClosed, (int)); 63 MOCK_METHOD(void, OnReadyToSend, ()); 64 MOCK_METHOD(void, OnTransportClosed, (RTCError)); 65 MOCK_METHOD(void, OnBufferedAmountLow, (int channel_id), (override)); 66 }; 67 68 static_assert(!std::is_abstract_v<MockDataChannelSink>); 69 70 class Peer { 71 public: 72 Peer() 73 : fake_dtls_transport_(kTransportName, kComponent), 74 simulated_clock_(1000), 75 env_(CreateEnvironment(&simulated_clock_)) { 76 auto socket_ptr = std::make_unique<dcsctp::MockDcSctpSocket>(); 77 socket_ = socket_ptr.get(); 78 79 auto mock_dcsctp_socket_factory = 80 std::make_unique<dcsctp::MockDcSctpSocketFactory>(); 81 EXPECT_CALL(*mock_dcsctp_socket_factory, Create) 82 .Times(1) 83 .WillOnce(Return(ByMove(std::move(socket_ptr)))); 84 85 sctp_transport_ = std::make_unique<DcSctpTransport>( 86 env_, Thread::Current(), &fake_dtls_transport_, 87 std::move(mock_dcsctp_socket_factory)); 88 sctp_transport_->SetDataChannelSink(&sink_); 89 sctp_transport_->SetOnConnectedCallback([this]() { sink_.OnConnected(); }); 90 } 91 92 FakeDtlsTransport fake_dtls_transport_; 93 SimulatedClock simulated_clock_; 94 Environment env_; 95 dcsctp::MockDcSctpSocket* socket_; 96 std::unique_ptr<DcSctpTransport> sctp_transport_; 97 NiceMock<MockDataChannelSink> sink_; 98 }; 99 } // namespace 100 101 TEST(DcSctpTransportTest, OpenSequence) { 102 AutoThread main_thread; 103 Peer peer_a; 104 peer_a.fake_dtls_transport_.SetWritable(true); 105 106 EXPECT_CALL(*peer_a.socket_, Connect) 107 .Times(1) 108 .WillOnce(Invoke(peer_a.sctp_transport_.get(), 109 &dcsctp::DcSctpSocketCallbacks::OnConnected)); 110 EXPECT_CALL(peer_a.sink_, OnReadyToSend); 111 EXPECT_CALL(peer_a.sink_, OnConnected); 112 peer_a.sctp_transport_->Start({.local_port = 5000, 113 .remote_port = 5000, 114 .max_message_size = 256 * 1024}); 115 } 116 117 // Tests that the close sequence invoked from one end results in the stream to 118 // be reset from both ends and all the proper signals are sent. 119 TEST(DcSctpTransportTest, CloseSequence) { 120 AutoThread main_thread; 121 Peer peer_a; 122 Peer peer_b; 123 peer_a.fake_dtls_transport_.SetDestination(&peer_b.fake_dtls_transport_, 124 false); 125 { 126 InSequence sequence; 127 128 EXPECT_CALL( 129 *peer_a.socket_, 130 SetStreamPriority(dcsctp::StreamID(1), 131 dcsctp::StreamPriority(kDefaultPriority.value()))); 132 EXPECT_CALL(*peer_a.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1)))) 133 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed)); 134 135 EXPECT_CALL(*peer_b.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1)))) 136 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed)); 137 138 EXPECT_CALL(peer_a.sink_, OnChannelClosing(1)).Times(0); 139 EXPECT_CALL(peer_b.sink_, OnChannelClosing(1)); 140 EXPECT_CALL(peer_a.sink_, OnChannelClosed(1)); 141 EXPECT_CALL(peer_b.sink_, OnChannelClosed(1)); 142 } 143 144 peer_a.sctp_transport_->Start({.local_port = 5000, 145 .remote_port = 5000, 146 .max_message_size = 256 * 1024}); 147 peer_b.sctp_transport_->Start({.local_port = 5000, 148 .remote_port = 5000, 149 .max_message_size = 256 * 1024}); 150 peer_a.sctp_transport_->OpenStream(1, kDefaultPriority); 151 peer_b.sctp_transport_->OpenStream(1, kDefaultPriority); 152 peer_a.sctp_transport_->ResetStream(1); 153 154 // Simulate the callbacks from the stream resets 155 dcsctp::StreamID streams[1] = {dcsctp::StreamID(1)}; 156 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get()) 157 ->OnStreamsResetPerformed(streams); 158 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get()) 159 ->OnIncomingStreamsReset(streams); 160 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get()) 161 ->OnIncomingStreamsReset(streams); 162 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get()) 163 ->OnStreamsResetPerformed(streams); 164 } 165 166 // Tests that the close sequence initiated from both peers at the same time 167 // terminates properly. Both peers will think they initiated it, so no 168 // OnClosingProcedureStartedRemotely should be called. 169 TEST(DcSctpTransportTest, CloseSequenceSimultaneous) { 170 AutoThread main_thread; 171 Peer peer_a; 172 Peer peer_b; 173 peer_a.fake_dtls_transport_.SetDestination(&peer_b.fake_dtls_transport_, 174 false); 175 { 176 InSequence sequence; 177 178 EXPECT_CALL(*peer_a.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1)))) 179 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed)); 180 181 EXPECT_CALL(*peer_b.socket_, ResetStreams(ElementsAre(dcsctp::StreamID(1)))) 182 .WillOnce(Return(dcsctp::ResetStreamsStatus::kPerformed)); 183 184 EXPECT_CALL(peer_a.sink_, OnChannelClosing(1)).Times(0); 185 EXPECT_CALL(peer_b.sink_, OnChannelClosing(1)).Times(0); 186 EXPECT_CALL(peer_a.sink_, OnChannelClosed(1)); 187 EXPECT_CALL(peer_b.sink_, OnChannelClosed(1)); 188 } 189 190 peer_a.sctp_transport_->Start({.local_port = 5000, 191 .remote_port = 5000, 192 .max_message_size = 256 * 1024}); 193 peer_b.sctp_transport_->Start({.local_port = 5000, 194 .remote_port = 5000, 195 .max_message_size = 256 * 1024}); 196 peer_a.sctp_transport_->OpenStream(1, kDefaultPriority); 197 peer_b.sctp_transport_->OpenStream(1, kDefaultPriority); 198 peer_a.sctp_transport_->ResetStream(1); 199 peer_b.sctp_transport_->ResetStream(1); 200 201 // Simulate the callbacks from the stream resets 202 dcsctp::StreamID streams[1] = {dcsctp::StreamID(1)}; 203 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get()) 204 ->OnStreamsResetPerformed(streams); 205 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get()) 206 ->OnStreamsResetPerformed(streams); 207 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get()) 208 ->OnIncomingStreamsReset(streams); 209 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_b.sctp_transport_.get()) 210 ->OnIncomingStreamsReset(streams); 211 } 212 213 TEST(DcSctpTransportTest, SetStreamPriority) { 214 AutoThread main_thread; 215 Peer peer_a; 216 217 { 218 InSequence sequence; 219 220 EXPECT_CALL( 221 *peer_a.socket_, 222 SetStreamPriority(dcsctp::StreamID(1), dcsctp::StreamPriority(1337))); 223 EXPECT_CALL( 224 *peer_a.socket_, 225 SetStreamPriority(dcsctp::StreamID(2), dcsctp::StreamPriority(3141))); 226 } 227 228 EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(0); 229 230 peer_a.sctp_transport_->OpenStream(1, PriorityValue(1337)); 231 peer_a.sctp_transport_->Start({.local_port = 5000, 232 .remote_port = 5000, 233 .max_message_size = 256 * 1024}); 234 peer_a.sctp_transport_->OpenStream(2, PriorityValue(3141)); 235 } 236 237 TEST(DcSctpTransportTest, DiscardMessageClosedChannel) { 238 AutoThread main_thread; 239 Peer peer_a; 240 241 EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(0); 242 243 peer_a.sctp_transport_->Start({.local_port = 5000, 244 .remote_port = 5000, 245 .max_message_size = 256 * 1024}); 246 247 SendDataParams params; 248 CopyOnWriteBuffer payload; 249 EXPECT_EQ(peer_a.sctp_transport_->SendData(1, params, payload).type(), 250 RTCErrorType::INVALID_STATE); 251 } 252 253 TEST(DcSctpTransportTest, DiscardMessageClosingChannel) { 254 AutoThread main_thread; 255 Peer peer_a; 256 257 EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(0); 258 259 peer_a.sctp_transport_->OpenStream(1, kDefaultPriority); 260 peer_a.sctp_transport_->Start({.local_port = 5000, 261 .remote_port = 5000, 262 .max_message_size = 256 * 1024}); 263 peer_a.sctp_transport_->ResetStream(1); 264 265 SendDataParams params; 266 CopyOnWriteBuffer payload; 267 EXPECT_EQ(peer_a.sctp_transport_->SendData(1, params, payload).type(), 268 RTCErrorType::INVALID_STATE); 269 } 270 271 TEST(DcSctpTransportTest, SendDataOpenChannel) { 272 AutoThread main_thread; 273 Peer peer_a; 274 dcsctp::DcSctpOptions options; 275 276 EXPECT_CALL(*peer_a.socket_, Send(_, _)).Times(1); 277 EXPECT_CALL(*peer_a.socket_, options()).WillOnce(ReturnPointee(&options)); 278 279 peer_a.sctp_transport_->OpenStream(1, kDefaultPriority); 280 peer_a.sctp_transport_->Start({.local_port = 5000, 281 .remote_port = 5000, 282 .max_message_size = 256 * 1024}); 283 284 SendDataParams params; 285 CopyOnWriteBuffer payload; 286 EXPECT_TRUE(peer_a.sctp_transport_->SendData(1, params, payload).ok()); 287 } 288 289 TEST(DcSctpTransportTest, DeliversMessage) { 290 AutoThread main_thread; 291 Peer peer_a; 292 293 EXPECT_CALL(peer_a.sink_, OnDataReceived(1, DataMessageType::kBinary, _)) 294 .Times(1); 295 296 peer_a.sctp_transport_->OpenStream(1, kDefaultPriority); 297 peer_a.sctp_transport_->Start({.local_port = 5000, 298 .remote_port = 5000, 299 .max_message_size = 256 * 1024}); 300 301 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get()) 302 ->OnMessageReceived( 303 dcsctp::DcSctpMessage(dcsctp::StreamID(1), dcsctp::PPID(53), {0})); 304 } 305 306 TEST(DcSctpTransportTest, DropMessageWithUnknownPpid) { 307 AutoThread main_thread; 308 Peer peer_a; 309 310 EXPECT_CALL(peer_a.sink_, OnDataReceived(_, _, _)).Times(0); 311 312 peer_a.sctp_transport_->OpenStream(1, kDefaultPriority); 313 peer_a.sctp_transport_->Start({.local_port = 5000, 314 .remote_port = 5000, 315 .max_message_size = 256 * 1024}); 316 317 static_cast<dcsctp::DcSctpSocketCallbacks*>(peer_a.sctp_transport_.get()) 318 ->OnMessageReceived( 319 dcsctp::DcSctpMessage(dcsctp::StreamID(1), dcsctp::PPID(1337), {0})); 320 } 321 } // namespace webrtc