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/peer_connection_proxy.h"
23 #include "api/scoped_refptr.h"
24 #include "api/task_queue/default_task_queue_factory.h"
25 #include "media/base/codec.h"
26 #include "media/base/fake_media_engine.h"
27 #include "media/base/media_constants.h"
28 #include "media/base/media_engine.h"
29 #include "media/sctp/sctp_transport_internal.h"
30 #include "p2p/base/p2p_constants.h"
31 #include "p2p/base/port_allocator.h"
32 #include "pc/media_session.h"
33 #include "pc/peer_connection.h"
34 #include "pc/peer_connection_factory.h"
35 #include "pc/peer_connection_wrapper.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/ref_counted_object.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 "pc/test/fake_sctp_transport.h"
49 #include "rtc_base/virtual_socket_server.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(rtc::Thread * network_thread,rtc::Thread * worker_thread,rtc::Thread * signaling_thread,std::unique_ptr<cricket::MediaEngineInterface> media_engine,std::unique_ptr<CallFactoryInterface> call_factory)61 PeerConnectionFactoryDependencies CreatePeerConnectionFactoryDependencies(
62 rtc::Thread* network_thread,
63 rtc::Thread* worker_thread,
64 rtc::Thread* signaling_thread,
65 std::unique_ptr<cricket::MediaEngineInterface> media_engine,
66 std::unique_ptr<CallFactoryInterface> call_factory) {
67 PeerConnectionFactoryDependencies deps;
68 deps.network_thread = network_thread;
69 deps.worker_thread = worker_thread;
70 deps.signaling_thread = signaling_thread;
71 deps.task_queue_factory = CreateDefaultTaskQueueFactory();
72 deps.media_engine = std::move(media_engine);
73 deps.call_factory = std::move(call_factory);
74 return deps;
75 }
76
77 } // namespace
78
79 class PeerConnectionFactoryForDataChannelTest
80 : public rtc::RefCountedObject<PeerConnectionFactory> {
81 public:
PeerConnectionFactoryForDataChannelTest()82 PeerConnectionFactoryForDataChannelTest()
83 : rtc::RefCountedObject<PeerConnectionFactory>(
84 CreatePeerConnectionFactoryDependencies(
85 rtc::Thread::Current(),
86 rtc::Thread::Current(),
87 rtc::Thread::Current(),
88 std::make_unique<cricket::FakeMediaEngine>(),
89 CreateCallFactory())) {}
90
91 std::unique_ptr<cricket::SctpTransportInternalFactory>
CreateSctpTransportInternalFactory()92 CreateSctpTransportInternalFactory() {
93 auto factory = std::make_unique<FakeSctpTransportFactory>();
94 last_fake_sctp_transport_factory_ = factory.get();
95 return factory;
96 }
97
98 FakeSctpTransportFactory* last_fake_sctp_transport_factory_ = nullptr;
99 };
100
101 class PeerConnectionWrapperForDataChannelTest : public PeerConnectionWrapper {
102 public:
103 using PeerConnectionWrapper::PeerConnectionWrapper;
104
sctp_transport_factory()105 FakeSctpTransportFactory* sctp_transport_factory() {
106 return sctp_transport_factory_;
107 }
108
set_sctp_transport_factory(FakeSctpTransportFactory * sctp_transport_factory)109 void set_sctp_transport_factory(
110 FakeSctpTransportFactory* sctp_transport_factory) {
111 sctp_transport_factory_ = sctp_transport_factory;
112 }
113
sctp_mid()114 absl::optional<std::string> sctp_mid() {
115 return GetInternalPeerConnection()->sctp_mid();
116 }
117
sctp_transport_name()118 absl::optional<std::string> sctp_transport_name() {
119 return GetInternalPeerConnection()->sctp_transport_name();
120 }
121
GetInternalPeerConnection()122 PeerConnection* GetInternalPeerConnection() {
123 auto* pci =
124 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
125 pc());
126 return static_cast<PeerConnection*>(pci->internal());
127 }
128
129 private:
130 FakeSctpTransportFactory* sctp_transport_factory_ = nullptr;
131 };
132
133 class PeerConnectionDataChannelBaseTest : public ::testing::Test {
134 protected:
135 typedef std::unique_ptr<PeerConnectionWrapperForDataChannelTest> WrapperPtr;
136
PeerConnectionDataChannelBaseTest(SdpSemantics sdp_semantics)137 explicit PeerConnectionDataChannelBaseTest(SdpSemantics sdp_semantics)
138 : vss_(new rtc::VirtualSocketServer()),
139 main_(vss_.get()),
140 sdp_semantics_(sdp_semantics) {
141 #ifdef WEBRTC_ANDROID
142 InitializeAndroidObjects();
143 #endif
144 }
145
CreatePeerConnection()146 WrapperPtr CreatePeerConnection() {
147 return CreatePeerConnection(RTCConfiguration());
148 }
149
CreatePeerConnection(const RTCConfiguration & config)150 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
151 return CreatePeerConnection(config,
152 PeerConnectionFactoryInterface::Options());
153 }
154
CreatePeerConnection(const RTCConfiguration & config,const PeerConnectionFactoryInterface::Options factory_options)155 WrapperPtr CreatePeerConnection(
156 const RTCConfiguration& config,
157 const PeerConnectionFactoryInterface::Options factory_options) {
158 rtc::scoped_refptr<PeerConnectionFactoryForDataChannelTest> pc_factory(
159 new PeerConnectionFactoryForDataChannelTest());
160 pc_factory->SetOptions(factory_options);
161 RTC_CHECK(pc_factory->Initialize());
162 auto observer = std::make_unique<MockPeerConnectionObserver>();
163 RTCConfiguration modified_config = config;
164 modified_config.sdp_semantics = sdp_semantics_;
165 auto pc = pc_factory->CreatePeerConnection(modified_config, nullptr,
166 nullptr, observer.get());
167 if (!pc) {
168 return nullptr;
169 }
170
171 observer->SetPeerConnectionInterface(pc.get());
172 auto wrapper = std::make_unique<PeerConnectionWrapperForDataChannelTest>(
173 pc_factory, pc, std::move(observer));
174 RTC_DCHECK(pc_factory->last_fake_sctp_transport_factory_);
175 wrapper->set_sctp_transport_factory(
176 pc_factory->last_fake_sctp_transport_factory_);
177 return wrapper;
178 }
179
180 // Accepts the same arguments as CreatePeerConnection and adds a default data
181 // channel.
182 template <typename... Args>
CreatePeerConnectionWithDataChannel(Args &&...args)183 WrapperPtr CreatePeerConnectionWithDataChannel(Args&&... args) {
184 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
185 if (!wrapper) {
186 return nullptr;
187 }
188 EXPECT_TRUE(wrapper->pc()->CreateDataChannel("dc", nullptr));
189 return wrapper;
190 }
191
192 // Changes the SCTP data channel port on the given session description.
ChangeSctpPortOnDescription(cricket::SessionDescription * desc,int port)193 void ChangeSctpPortOnDescription(cricket::SessionDescription* desc,
194 int port) {
195 auto* data_content = cricket::GetFirstDataContent(desc);
196 RTC_DCHECK(data_content);
197 auto* data_desc = data_content->media_description()->as_sctp();
198 RTC_DCHECK(data_desc);
199 data_desc->set_port(port);
200 }
201
202 std::unique_ptr<rtc::VirtualSocketServer> vss_;
203 rtc::AutoSocketServerThread main_;
204 const SdpSemantics sdp_semantics_;
205 };
206
207 class PeerConnectionDataChannelTest
208 : public PeerConnectionDataChannelBaseTest,
209 public ::testing::WithParamInterface<SdpSemantics> {
210 protected:
PeerConnectionDataChannelTest()211 PeerConnectionDataChannelTest()
212 : PeerConnectionDataChannelBaseTest(GetParam()) {}
213 };
214
215 class PeerConnectionDataChannelUnifiedPlanTest
216 : public PeerConnectionDataChannelBaseTest {
217 protected:
PeerConnectionDataChannelUnifiedPlanTest()218 PeerConnectionDataChannelUnifiedPlanTest()
219 : PeerConnectionDataChannelBaseTest(SdpSemantics::kUnifiedPlan) {}
220 };
221
TEST_P(PeerConnectionDataChannelTest,NoSctpTransportCreatedIfRtpDataChannelEnabled)222 TEST_P(PeerConnectionDataChannelTest,
223 NoSctpTransportCreatedIfRtpDataChannelEnabled) {
224 RTCConfiguration config;
225 config.enable_rtp_data_channel = true;
226 auto caller = CreatePeerConnectionWithDataChannel(config);
227
228 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
229 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
230 }
231
TEST_P(PeerConnectionDataChannelTest,RtpDataChannelCreatedEvenIfSctpAvailable)232 TEST_P(PeerConnectionDataChannelTest,
233 RtpDataChannelCreatedEvenIfSctpAvailable) {
234 RTCConfiguration config;
235 config.enable_rtp_data_channel = true;
236 PeerConnectionFactoryInterface::Options options;
237 options.disable_sctp_data_channels = false;
238 auto caller = CreatePeerConnectionWithDataChannel(config, options);
239
240 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
241 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
242 }
243
TEST_P(PeerConnectionDataChannelTest,InternalSctpTransportDeletedOnTeardown)244 TEST_P(PeerConnectionDataChannelTest, InternalSctpTransportDeletedOnTeardown) {
245 auto caller = CreatePeerConnectionWithDataChannel();
246
247 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
248 EXPECT_TRUE(caller->sctp_transport_factory()->last_fake_sctp_transport());
249
250 rtc::scoped_refptr<SctpTransportInterface> sctp_transport =
251 caller->GetInternalPeerConnection()->GetSctpTransport();
252
253 caller.reset();
254 EXPECT_EQ(static_cast<SctpTransport*>(sctp_transport.get())->internal(),
255 nullptr);
256 }
257
258 // Test that sctp_mid/sctp_transport_name (used for stats) are correct
259 // before and after BUNDLE is negotiated.
TEST_P(PeerConnectionDataChannelTest,SctpContentAndTransportNameSetCorrectly)260 TEST_P(PeerConnectionDataChannelTest, SctpContentAndTransportNameSetCorrectly) {
261 auto caller = CreatePeerConnection();
262 auto callee = CreatePeerConnection();
263
264 // Initially these fields should be empty.
265 EXPECT_FALSE(caller->sctp_mid());
266 EXPECT_FALSE(caller->sctp_transport_name());
267
268 // Create offer with audio/video/data.
269 // Default bundle policy is "balanced", so data should be using its own
270 // transport.
271 caller->AddAudioTrack("a");
272 caller->AddVideoTrack("v");
273 caller->pc()->CreateDataChannel("dc", nullptr);
274
275 auto offer = caller->CreateOffer();
276 const auto& offer_contents = offer->description()->contents();
277 ASSERT_EQ(cricket::MEDIA_TYPE_AUDIO,
278 offer_contents[0].media_description()->type());
279 std::string audio_mid = offer_contents[0].name;
280 ASSERT_EQ(cricket::MEDIA_TYPE_DATA,
281 offer_contents[2].media_description()->type());
282 std::string data_mid = offer_contents[2].name;
283
284 ASSERT_TRUE(
285 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
286 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
287
288 ASSERT_TRUE(caller->sctp_mid());
289 EXPECT_EQ(data_mid, *caller->sctp_mid());
290 ASSERT_TRUE(caller->sctp_transport_name());
291 EXPECT_EQ(data_mid, *caller->sctp_transport_name());
292
293 // Create answer that finishes BUNDLE negotiation, which means everything
294 // should be bundled on the first transport (audio).
295 RTCOfferAnswerOptions options;
296 options.use_rtp_mux = true;
297 ASSERT_TRUE(
298 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
299
300 ASSERT_TRUE(caller->sctp_mid());
301 EXPECT_EQ(data_mid, *caller->sctp_mid());
302 ASSERT_TRUE(caller->sctp_transport_name());
303 EXPECT_EQ(audio_mid, *caller->sctp_transport_name());
304 }
305
TEST_P(PeerConnectionDataChannelTest,CreateOfferWithNoDataChannelsGivesNoDataSection)306 TEST_P(PeerConnectionDataChannelTest,
307 CreateOfferWithNoDataChannelsGivesNoDataSection) {
308 auto caller = CreatePeerConnection();
309 auto offer = caller->CreateOffer();
310
311 EXPECT_FALSE(offer->description()->GetContentByName(cricket::CN_DATA));
312 EXPECT_FALSE(offer->description()->GetTransportInfoByName(cricket::CN_DATA));
313 }
314
TEST_P(PeerConnectionDataChannelTest,CreateAnswerWithRemoteSctpDataChannelIncludesDataSection)315 TEST_P(PeerConnectionDataChannelTest,
316 CreateAnswerWithRemoteSctpDataChannelIncludesDataSection) {
317 auto caller = CreatePeerConnectionWithDataChannel();
318 auto callee = CreatePeerConnection();
319
320 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
321
322 auto answer = callee->CreateAnswer();
323 ASSERT_TRUE(answer);
324 auto* data_content = cricket::GetFirstDataContent(answer->description());
325 ASSERT_TRUE(data_content);
326 EXPECT_FALSE(data_content->rejected);
327 EXPECT_TRUE(
328 answer->description()->GetTransportInfoByName(data_content->name));
329 }
330
TEST_P(PeerConnectionDataChannelTest,CreateDataChannelWithDtlsDisabledSucceeds)331 TEST_P(PeerConnectionDataChannelTest,
332 CreateDataChannelWithDtlsDisabledSucceeds) {
333 RTCConfiguration config;
334 config.enable_dtls_srtp.emplace(false);
335 auto caller = CreatePeerConnection();
336
337 EXPECT_TRUE(caller->pc()->CreateDataChannel("dc", nullptr));
338 }
339
TEST_P(PeerConnectionDataChannelTest,CreateDataChannelWithSctpDisabledFails)340 TEST_P(PeerConnectionDataChannelTest, CreateDataChannelWithSctpDisabledFails) {
341 PeerConnectionFactoryInterface::Options options;
342 options.disable_sctp_data_channels = true;
343 auto caller = CreatePeerConnection(RTCConfiguration(), options);
344
345 EXPECT_FALSE(caller->pc()->CreateDataChannel("dc", nullptr));
346 }
347
348 // Test that if a callee has SCTP disabled and receives an offer with an SCTP
349 // data channel, the data section is rejected and no SCTP transport is created
350 // on the callee.
TEST_P(PeerConnectionDataChannelTest,DataSectionRejectedIfCalleeHasSctpDisabled)351 TEST_P(PeerConnectionDataChannelTest,
352 DataSectionRejectedIfCalleeHasSctpDisabled) {
353 auto caller = CreatePeerConnectionWithDataChannel();
354 PeerConnectionFactoryInterface::Options options;
355 options.disable_sctp_data_channels = true;
356 auto callee = CreatePeerConnection(RTCConfiguration(), options);
357
358 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
359
360 EXPECT_FALSE(callee->sctp_transport_factory()->last_fake_sctp_transport());
361
362 auto answer = callee->CreateAnswer();
363 auto* data_content = cricket::GetFirstDataContent(answer->description());
364 ASSERT_TRUE(data_content);
365 EXPECT_TRUE(data_content->rejected);
366 }
367
TEST_P(PeerConnectionDataChannelTest,SctpPortPropagatedFromSdpToTransport)368 TEST_P(PeerConnectionDataChannelTest, SctpPortPropagatedFromSdpToTransport) {
369 constexpr int kNewSendPort = 9998;
370 constexpr int kNewRecvPort = 7775;
371
372 auto caller = CreatePeerConnectionWithDataChannel();
373 auto callee = CreatePeerConnectionWithDataChannel();
374
375 auto offer = caller->CreateOffer();
376 ChangeSctpPortOnDescription(offer->description(), kNewSendPort);
377 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
378
379 auto answer = callee->CreateAnswer();
380 ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
381 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
382
383 auto* callee_transport =
384 callee->sctp_transport_factory()->last_fake_sctp_transport();
385 ASSERT_TRUE(callee_transport);
386 EXPECT_EQ(kNewSendPort, callee_transport->remote_port());
387 EXPECT_EQ(kNewRecvPort, callee_transport->local_port());
388 }
389
TEST_P(PeerConnectionDataChannelTest,ModernSdpSyntaxByDefault)390 TEST_P(PeerConnectionDataChannelTest, ModernSdpSyntaxByDefault) {
391 PeerConnectionInterface::RTCOfferAnswerOptions options;
392 auto caller = CreatePeerConnectionWithDataChannel();
393 auto offer = caller->CreateOffer(options);
394 EXPECT_FALSE(cricket::GetFirstSctpDataContentDescription(offer->description())
395 ->use_sctpmap());
396 std::string sdp;
397 offer->ToString(&sdp);
398 RTC_LOG(LS_ERROR) << sdp;
399 EXPECT_THAT(sdp, HasSubstr(" UDP/DTLS/SCTP webrtc-datachannel"));
400 EXPECT_THAT(sdp, Not(HasSubstr("a=sctpmap:")));
401 }
402
TEST_P(PeerConnectionDataChannelTest,ObsoleteSdpSyntaxIfSet)403 TEST_P(PeerConnectionDataChannelTest, ObsoleteSdpSyntaxIfSet) {
404 PeerConnectionInterface::RTCOfferAnswerOptions options;
405 options.use_obsolete_sctp_sdp = true;
406 auto caller = CreatePeerConnectionWithDataChannel();
407 auto offer = caller->CreateOffer(options);
408 EXPECT_TRUE(cricket::GetFirstSctpDataContentDescription(offer->description())
409 ->use_sctpmap());
410 std::string sdp;
411 offer->ToString(&sdp);
412 EXPECT_THAT(sdp, Not(HasSubstr(" UDP/DTLS/SCTP webrtc-datachannel")));
413 EXPECT_THAT(sdp, HasSubstr("a=sctpmap:"));
414 }
415
416 INSTANTIATE_TEST_SUITE_P(PeerConnectionDataChannelTest,
417 PeerConnectionDataChannelTest,
418 Values(SdpSemantics::kPlanB,
419 SdpSemantics::kUnifiedPlan));
420
TEST_F(PeerConnectionDataChannelUnifiedPlanTest,ReOfferAfterPeerRejectsDataChannel)421 TEST_F(PeerConnectionDataChannelUnifiedPlanTest,
422 ReOfferAfterPeerRejectsDataChannel) {
423 auto caller = CreatePeerConnectionWithDataChannel();
424 PeerConnectionFactoryInterface::Options options;
425 options.disable_sctp_data_channels = true;
426 auto callee = CreatePeerConnection(RTCConfiguration(), options);
427
428 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
429
430 auto offer = caller->CreateOffer();
431 ASSERT_TRUE(offer);
432 const auto& contents = offer->description()->contents();
433 ASSERT_EQ(1u, contents.size());
434 EXPECT_TRUE(contents[0].rejected);
435
436 ASSERT_TRUE(
437 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
438 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
439
440 auto answer = callee->CreateAnswerAndSetAsLocal();
441 ASSERT_TRUE(answer);
442 EXPECT_TRUE(caller->SetRemoteDescription(std::move(answer)));
443 }
444
445 } // namespace webrtc
446