1 /*
2 * Copyright 2017 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 <memory>
12 #include <string>
13 #include <type_traits>
14 #include <utility>
15 #include <vector>
16
17 #include "absl/types/optional.h"
18 #include "api/call/call_factory_interface.h"
19 #include "api/jsep.h"
20 #include "api/media_types.h"
21 #include "api/peer_connection_interface.h"
22 #include "api/scoped_refptr.h"
23 #include "api/sctp_transport_interface.h"
24 #include "api/task_queue/default_task_queue_factory.h"
25 #include "api/task_queue/task_queue_factory.h"
26 #include "api/transport/sctp_transport_factory_interface.h"
27 #include "media/base/fake_media_engine.h"
28 #include "media/base/media_engine.h"
29 #include "p2p/base/p2p_constants.h"
30 #include "p2p/base/port_allocator.h"
31 #include "pc/media_session.h"
32 #include "pc/peer_connection.h"
33 #include "pc/peer_connection_proxy.h"
34 #include "pc/peer_connection_wrapper.h"
35 #include "pc/sctp_transport.h"
36 #include "pc/sdp_utils.h"
37 #include "pc/session_description.h"
38 #include "pc/test/mock_peer_connection_observers.h"
39 #include "rtc_base/checks.h"
40 #include "rtc_base/logging.h"
41 #include "rtc_base/rtc_certificate_generator.h"
42 #include "rtc_base/thread.h"
43 #include "test/gmock.h"
44 #include "test/gtest.h"
45 #ifdef WEBRTC_ANDROID
46 #include "pc/test/android_test_initializer.h"
47 #endif
48 #include "rtc_base/virtual_socket_server.h"
49 #include "test/pc/sctp/fake_sctp_transport.h"
50
51 namespace webrtc {
52
53 using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
54 using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
55 using ::testing::HasSubstr;
56 using ::testing::Not;
57 using ::testing::Values;
58
59 namespace {
60
CreatePeerConnectionFactoryDependencies()61 PeerConnectionFactoryDependencies CreatePeerConnectionFactoryDependencies() {
62 PeerConnectionFactoryDependencies deps;
63 deps.network_thread = rtc::Thread::Current();
64 deps.worker_thread = rtc::Thread::Current();
65 deps.signaling_thread = rtc::Thread::Current();
66 deps.task_queue_factory = CreateDefaultTaskQueueFactory();
67 deps.media_engine = std::make_unique<cricket::FakeMediaEngine>();
68 deps.call_factory = CreateCallFactory();
69 deps.sctp_factory = std::make_unique<FakeSctpTransportFactory>();
70 return deps;
71 }
72
73 } // namespace
74
75 class PeerConnectionWrapperForDataChannelTest : public PeerConnectionWrapper {
76 public:
77 using PeerConnectionWrapper::PeerConnectionWrapper;
78
sctp_transport_factory()79 FakeSctpTransportFactory* sctp_transport_factory() {
80 return sctp_transport_factory_;
81 }
82
set_sctp_transport_factory(FakeSctpTransportFactory * sctp_transport_factory)83 void set_sctp_transport_factory(
84 FakeSctpTransportFactory* sctp_transport_factory) {
85 sctp_transport_factory_ = sctp_transport_factory;
86 }
87
sctp_mid()88 absl::optional<std::string> sctp_mid() {
89 return GetInternalPeerConnection()->sctp_mid();
90 }
91
sctp_transport_name()92 absl::optional<std::string> sctp_transport_name() {
93 return GetInternalPeerConnection()->sctp_transport_name();
94 }
95
GetInternalPeerConnection()96 PeerConnection* GetInternalPeerConnection() {
97 auto* pci =
98 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
99 pc());
100 return static_cast<PeerConnection*>(pci->internal());
101 }
102
103 private:
104 FakeSctpTransportFactory* sctp_transport_factory_ = nullptr;
105 };
106
107 class PeerConnectionDataChannelBaseTest : public ::testing::Test {
108 protected:
109 typedef std::unique_ptr<PeerConnectionWrapperForDataChannelTest> WrapperPtr;
110
PeerConnectionDataChannelBaseTest(SdpSemantics sdp_semantics)111 explicit PeerConnectionDataChannelBaseTest(SdpSemantics sdp_semantics)
112 : vss_(new rtc::VirtualSocketServer()),
113 main_(vss_.get()),
114 sdp_semantics_(sdp_semantics) {
115 #ifdef WEBRTC_ANDROID
116 InitializeAndroidObjects();
117 #endif
118 }
119
CreatePeerConnection()120 WrapperPtr CreatePeerConnection() {
121 return CreatePeerConnection(RTCConfiguration());
122 }
123
CreatePeerConnection(const RTCConfiguration & config)124 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
125 return CreatePeerConnection(config,
126 PeerConnectionFactoryInterface::Options());
127 }
128
CreatePeerConnection(const RTCConfiguration & config,const PeerConnectionFactoryInterface::Options factory_options)129 WrapperPtr CreatePeerConnection(
130 const RTCConfiguration& config,
131 const PeerConnectionFactoryInterface::Options factory_options) {
132 auto factory_deps = CreatePeerConnectionFactoryDependencies();
133 FakeSctpTransportFactory* fake_sctp_transport_factory =
134 static_cast<FakeSctpTransportFactory*>(factory_deps.sctp_factory.get());
135 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory =
136 CreateModularPeerConnectionFactory(std::move(factory_deps));
137 pc_factory->SetOptions(factory_options);
138 auto observer = std::make_unique<MockPeerConnectionObserver>();
139 RTCConfiguration modified_config = config;
140 modified_config.sdp_semantics = sdp_semantics_;
141 auto result = pc_factory->CreatePeerConnectionOrError(
142 modified_config, PeerConnectionDependencies(observer.get()));
143 if (!result.ok()) {
144 return nullptr;
145 }
146
147 observer->SetPeerConnectionInterface(result.value().get());
148 auto wrapper = std::make_unique<PeerConnectionWrapperForDataChannelTest>(
149 pc_factory, result.MoveValue(), std::move(observer));
150 wrapper->set_sctp_transport_factory(fake_sctp_transport_factory);
151 return wrapper;
152 }
153
154 // Accepts the same arguments as CreatePeerConnection and adds a default data
155 // channel.
156 template <typename... Args>
CreatePeerConnectionWithDataChannel(Args &&...args)157 WrapperPtr CreatePeerConnectionWithDataChannel(Args&&... args) {
158 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
159 if (!wrapper) {
160 return nullptr;
161 }
162 EXPECT_TRUE(wrapper->pc()->CreateDataChannelOrError("dc", nullptr).ok());
163 return wrapper;
164 }
165
166 // Changes the SCTP data channel port on the given session description.
ChangeSctpPortOnDescription(cricket::SessionDescription * desc,int port)167 void ChangeSctpPortOnDescription(cricket::SessionDescription* desc,
168 int port) {
169 auto* data_content = cricket::GetFirstDataContent(desc);
170 RTC_DCHECK(data_content);
171 auto* data_desc = data_content->media_description()->as_sctp();
172 RTC_DCHECK(data_desc);
173 data_desc->set_port(port);
174 }
175
176 std::unique_ptr<rtc::VirtualSocketServer> vss_;
177 rtc::AutoSocketServerThread main_;
178 const SdpSemantics sdp_semantics_;
179 };
180
181 class PeerConnectionDataChannelTest
182 : public PeerConnectionDataChannelBaseTest,
183 public ::testing::WithParamInterface<SdpSemantics> {
184 protected:
PeerConnectionDataChannelTest()185 PeerConnectionDataChannelTest()
186 : PeerConnectionDataChannelBaseTest(GetParam()) {}
187 };
188
189 class PeerConnectionDataChannelUnifiedPlanTest
190 : public PeerConnectionDataChannelBaseTest {
191 protected:
PeerConnectionDataChannelUnifiedPlanTest()192 PeerConnectionDataChannelUnifiedPlanTest()
193 : PeerConnectionDataChannelBaseTest(SdpSemantics::kUnifiedPlan) {}
194 };
195
TEST_P(PeerConnectionDataChannelTest,InternalSctpTransportDeletedOnTeardown)196 TEST_P(PeerConnectionDataChannelTest, InternalSctpTransportDeletedOnTeardown) {
197 auto caller = CreatePeerConnectionWithDataChannel();
198
199 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
200 EXPECT_TRUE(caller->sctp_transport_factory()->last_fake_sctp_transport());
201
202 rtc::scoped_refptr<SctpTransportInterface> sctp_transport =
203 caller->GetInternalPeerConnection()->GetSctpTransport();
204
205 caller.reset();
206 EXPECT_EQ(static_cast<SctpTransport*>(sctp_transport.get())->internal(),
207 nullptr);
208 }
209
210 // Test that sctp_mid/sctp_transport_name (used for stats) are correct
211 // before and after BUNDLE is negotiated.
TEST_P(PeerConnectionDataChannelTest,SctpContentAndTransportNameSetCorrectly)212 TEST_P(PeerConnectionDataChannelTest, SctpContentAndTransportNameSetCorrectly) {
213 auto caller = CreatePeerConnection();
214 auto callee = CreatePeerConnection();
215
216 // Initially these fields should be empty.
217 EXPECT_FALSE(caller->sctp_mid());
218 EXPECT_FALSE(caller->sctp_transport_name());
219
220 // Create offer with audio/video/data.
221 // Default bundle policy is "balanced", so data should be using its own
222 // transport.
223 caller->AddAudioTrack("a");
224 caller->AddVideoTrack("v");
225 caller->pc()->CreateDataChannelOrError("dc", nullptr);
226
227 auto offer = caller->CreateOffer();
228 const auto& offer_contents = offer->description()->contents();
229 ASSERT_EQ(cricket::MEDIA_TYPE_AUDIO,
230 offer_contents[0].media_description()->type());
231 std::string audio_mid = offer_contents[0].name;
232 ASSERT_EQ(cricket::MEDIA_TYPE_DATA,
233 offer_contents[2].media_description()->type());
234 std::string data_mid = offer_contents[2].name;
235
236 ASSERT_TRUE(
237 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
238 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
239
240 ASSERT_TRUE(caller->sctp_mid());
241 EXPECT_EQ(data_mid, *caller->sctp_mid());
242 ASSERT_TRUE(caller->sctp_transport_name());
243 EXPECT_EQ(data_mid, *caller->sctp_transport_name());
244
245 // Create answer that finishes BUNDLE negotiation, which means everything
246 // should be bundled on the first transport (audio).
247 RTCOfferAnswerOptions options;
248 options.use_rtp_mux = true;
249 ASSERT_TRUE(
250 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
251
252 ASSERT_TRUE(caller->sctp_mid());
253 EXPECT_EQ(data_mid, *caller->sctp_mid());
254 ASSERT_TRUE(caller->sctp_transport_name());
255 EXPECT_EQ(audio_mid, *caller->sctp_transport_name());
256 }
257
TEST_P(PeerConnectionDataChannelTest,CreateOfferWithNoDataChannelsGivesNoDataSection)258 TEST_P(PeerConnectionDataChannelTest,
259 CreateOfferWithNoDataChannelsGivesNoDataSection) {
260 auto caller = CreatePeerConnection();
261 auto offer = caller->CreateOffer();
262
263 EXPECT_FALSE(offer->description()->GetContentByName(cricket::CN_DATA));
264 EXPECT_FALSE(offer->description()->GetTransportInfoByName(cricket::CN_DATA));
265 }
266
TEST_P(PeerConnectionDataChannelTest,CreateAnswerWithRemoteSctpDataChannelIncludesDataSection)267 TEST_P(PeerConnectionDataChannelTest,
268 CreateAnswerWithRemoteSctpDataChannelIncludesDataSection) {
269 auto caller = CreatePeerConnectionWithDataChannel();
270 auto callee = CreatePeerConnection();
271
272 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
273
274 auto answer = callee->CreateAnswer();
275 ASSERT_TRUE(answer);
276 auto* data_content = cricket::GetFirstDataContent(answer->description());
277 ASSERT_TRUE(data_content);
278 EXPECT_FALSE(data_content->rejected);
279 EXPECT_TRUE(
280 answer->description()->GetTransportInfoByName(data_content->name));
281 }
282
TEST_P(PeerConnectionDataChannelTest,SctpPortPropagatedFromSdpToTransport)283 TEST_P(PeerConnectionDataChannelTest, SctpPortPropagatedFromSdpToTransport) {
284 constexpr int kNewSendPort = 9998;
285 constexpr int kNewRecvPort = 7775;
286
287 auto caller = CreatePeerConnectionWithDataChannel();
288 auto callee = CreatePeerConnectionWithDataChannel();
289
290 auto offer = caller->CreateOffer();
291 ChangeSctpPortOnDescription(offer->description(), kNewSendPort);
292 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
293
294 auto answer = callee->CreateAnswer();
295 ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
296 std::string sdp;
297 answer->ToString(&sdp);
298 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
299 auto* callee_transport =
300 callee->sctp_transport_factory()->last_fake_sctp_transport();
301 ASSERT_TRUE(callee_transport);
302 EXPECT_EQ(kNewSendPort, callee_transport->remote_port());
303 EXPECT_EQ(kNewRecvPort, callee_transport->local_port());
304 }
305
TEST_P(PeerConnectionDataChannelTest,ModernSdpSyntaxByDefault)306 TEST_P(PeerConnectionDataChannelTest, ModernSdpSyntaxByDefault) {
307 PeerConnectionInterface::RTCOfferAnswerOptions options;
308 auto caller = CreatePeerConnectionWithDataChannel();
309 auto offer = caller->CreateOffer(options);
310 EXPECT_FALSE(cricket::GetFirstSctpDataContentDescription(offer->description())
311 ->use_sctpmap());
312 std::string sdp;
313 offer->ToString(&sdp);
314 RTC_LOG(LS_ERROR) << sdp;
315 EXPECT_THAT(sdp, HasSubstr(" UDP/DTLS/SCTP webrtc-datachannel"));
316 EXPECT_THAT(sdp, Not(HasSubstr("a=sctpmap:")));
317 }
318
TEST_P(PeerConnectionDataChannelTest,ObsoleteSdpSyntaxIfSet)319 TEST_P(PeerConnectionDataChannelTest, ObsoleteSdpSyntaxIfSet) {
320 PeerConnectionInterface::RTCOfferAnswerOptions options;
321 options.use_obsolete_sctp_sdp = true;
322 auto caller = CreatePeerConnectionWithDataChannel();
323 auto offer = caller->CreateOffer(options);
324 EXPECT_TRUE(cricket::GetFirstSctpDataContentDescription(offer->description())
325 ->use_sctpmap());
326 std::string sdp;
327 offer->ToString(&sdp);
328 EXPECT_THAT(sdp, Not(HasSubstr(" UDP/DTLS/SCTP webrtc-datachannel")));
329 EXPECT_THAT(sdp, HasSubstr("a=sctpmap:"));
330 }
331
332 INSTANTIATE_TEST_SUITE_P(PeerConnectionDataChannelTest,
333 PeerConnectionDataChannelTest,
334 Values(SdpSemantics::kPlanB_DEPRECATED,
335 SdpSemantics::kUnifiedPlan));
336
337 } // namespace webrtc
338