• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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