blob: db6c6568bdcb6461057e50ab0d8dcbc4a14a9cf8 [file] [log] [blame]
Steve Antonda6c0952017-10-23 11:41:54 -07001/*
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 <tuple>
12
13#include "api/peerconnectionproxy.h"
14#include "media/base/fakemediaengine.h"
15#include "pc/mediasession.h"
16#include "pc/peerconnection.h"
17#include "pc/peerconnectionfactory.h"
18#include "pc/peerconnectionwrapper.h"
Steve Antondbf9d032018-01-19 15:23:40 -080019#include "pc/sdputils.h"
Steve Antonda6c0952017-10-23 11:41:54 -070020#ifdef WEBRTC_ANDROID
21#include "pc/test/androidtestinitializer.h"
22#endif
23#include "pc/test/fakesctptransport.h"
24#include "rtc_base/gunit.h"
25#include "rtc_base/ptr_util.h"
26#include "rtc_base/virtualsocketserver.h"
27
28namespace webrtc {
29
30using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
31using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
32using ::testing::Values;
33
34class PeerConnectionFactoryForDataChannelTest
35 : public rtc::RefCountedObject<PeerConnectionFactory> {
36 public:
37 PeerConnectionFactoryForDataChannelTest()
38 : rtc::RefCountedObject<PeerConnectionFactory>(
39 rtc::Thread::Current(),
40 rtc::Thread::Current(),
41 rtc::Thread::Current(),
42 rtc::MakeUnique<cricket::FakeMediaEngine>(),
43 CreateCallFactory(),
44 nullptr) {}
45
46 std::unique_ptr<cricket::SctpTransportInternalFactory>
47 CreateSctpTransportInternalFactory() {
48 auto factory = rtc::MakeUnique<FakeSctpTransportFactory>();
49 last_fake_sctp_transport_factory_ = factory.get();
50 return factory;
51 }
52
53 FakeSctpTransportFactory* last_fake_sctp_transport_factory_ = nullptr;
54};
55
56class PeerConnectionWrapperForDataChannelTest : public PeerConnectionWrapper {
57 public:
58 using PeerConnectionWrapper::PeerConnectionWrapper;
59
60 FakeSctpTransportFactory* sctp_transport_factory() {
61 return sctp_transport_factory_;
62 }
63
64 void set_sctp_transport_factory(
65 FakeSctpTransportFactory* sctp_transport_factory) {
66 sctp_transport_factory_ = sctp_transport_factory;
67 }
68
69 rtc::Optional<std::string> sctp_content_name() {
70 return GetInternalPeerConnection()->sctp_content_name();
71 }
72
73 rtc::Optional<std::string> sctp_transport_name() {
74 return GetInternalPeerConnection()->sctp_transport_name();
75 }
76
77 PeerConnection* GetInternalPeerConnection() {
Mirko Bonadeie97de912017-12-13 11:29:34 +010078 auto* pci =
79 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
80 pc());
81 return static_cast<PeerConnection*>(pci->internal());
Steve Antonda6c0952017-10-23 11:41:54 -070082 }
83
84 private:
85 FakeSctpTransportFactory* sctp_transport_factory_ = nullptr;
86};
87
Steve Antondbf9d032018-01-19 15:23:40 -080088class PeerConnectionDataChannelBaseTest : public ::testing::Test {
Steve Antonda6c0952017-10-23 11:41:54 -070089 protected:
90 typedef std::unique_ptr<PeerConnectionWrapperForDataChannelTest> WrapperPtr;
91
Steve Antondbf9d032018-01-19 15:23:40 -080092 explicit PeerConnectionDataChannelBaseTest(SdpSemantics sdp_semantics)
93 : vss_(new rtc::VirtualSocketServer()),
94 main_(vss_.get()),
95 sdp_semantics_(sdp_semantics) {
Steve Antonda6c0952017-10-23 11:41:54 -070096#ifdef WEBRTC_ANDROID
97 InitializeAndroidObjects();
98#endif
99 }
100
101 WrapperPtr CreatePeerConnection() {
102 return CreatePeerConnection(RTCConfiguration());
103 }
104
105 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
106 return CreatePeerConnection(config,
107 PeerConnectionFactoryInterface::Options());
108 }
109
110 WrapperPtr CreatePeerConnection(
111 const RTCConfiguration& config,
112 const PeerConnectionFactoryInterface::Options factory_options) {
113 rtc::scoped_refptr<PeerConnectionFactoryForDataChannelTest> pc_factory(
114 new PeerConnectionFactoryForDataChannelTest());
115 pc_factory->SetOptions(factory_options);
116 RTC_CHECK(pc_factory->Initialize());
117 auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
Steve Antondbf9d032018-01-19 15:23:40 -0800118 RTCConfiguration modified_config = config;
119 modified_config.sdp_semantics = sdp_semantics_;
120 auto pc = pc_factory->CreatePeerConnection(modified_config, nullptr,
121 nullptr, observer.get());
Steve Antonda6c0952017-10-23 11:41:54 -0700122 if (!pc) {
123 return nullptr;
124 }
125
126 auto wrapper = rtc::MakeUnique<PeerConnectionWrapperForDataChannelTest>(
127 pc_factory, pc, std::move(observer));
128 RTC_DCHECK(pc_factory->last_fake_sctp_transport_factory_);
129 wrapper->set_sctp_transport_factory(
130 pc_factory->last_fake_sctp_transport_factory_);
131 return wrapper;
132 }
133
134 // Accepts the same arguments as CreatePeerConnection and adds a default data
135 // channel.
136 template <typename... Args>
137 WrapperPtr CreatePeerConnectionWithDataChannel(Args&&... args) {
138 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
139 if (!wrapper) {
140 return nullptr;
141 }
142 EXPECT_TRUE(wrapper->pc()->CreateDataChannel("dc", nullptr));
143 return wrapper;
144 }
145
146 // Changes the SCTP data channel port on the given session description.
147 void ChangeSctpPortOnDescription(cricket::SessionDescription* desc,
148 int port) {
149 cricket::DataCodec sctp_codec(cricket::kGoogleSctpDataCodecPlType,
150 cricket::kGoogleSctpDataCodecName);
151 sctp_codec.SetParam(cricket::kCodecParamPort, port);
152
153 auto* data_content = cricket::GetFirstDataContent(desc);
154 RTC_DCHECK(data_content);
Steve Antonb1c1de12017-12-21 15:14:30 -0800155 auto* data_desc = data_content->media_description()->as_data();
Steve Antonda6c0952017-10-23 11:41:54 -0700156 data_desc->set_codecs({sctp_codec});
157 }
158
159 std::unique_ptr<rtc::VirtualSocketServer> vss_;
160 rtc::AutoSocketServerThread main_;
Steve Antondbf9d032018-01-19 15:23:40 -0800161 const SdpSemantics sdp_semantics_;
Steve Antonda6c0952017-10-23 11:41:54 -0700162};
163
Steve Antondbf9d032018-01-19 15:23:40 -0800164class PeerConnectionDataChannelTest
165 : public PeerConnectionDataChannelBaseTest,
166 public ::testing::WithParamInterface<SdpSemantics> {
167 protected:
168 PeerConnectionDataChannelTest()
169 : PeerConnectionDataChannelBaseTest(GetParam()) {}
170};
171
172TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700173 NoSctpTransportCreatedIfRtpDataChannelEnabled) {
174 RTCConfiguration config;
175 config.enable_rtp_data_channel = true;
176 auto caller = CreatePeerConnectionWithDataChannel(config);
177
178 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
179 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
180}
181
Steve Antondbf9d032018-01-19 15:23:40 -0800182TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700183 RtpDataChannelCreatedEvenIfSctpAvailable) {
184 RTCConfiguration config;
185 config.enable_rtp_data_channel = true;
186 PeerConnectionFactoryInterface::Options options;
187 options.disable_sctp_data_channels = false;
188 auto caller = CreatePeerConnectionWithDataChannel(config, options);
189
190 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
191 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
192}
193
194// Test that sctp_content_name/sctp_transport_name (used for stats) are correct
195// before and after BUNDLE is negotiated.
Steve Antondbf9d032018-01-19 15:23:40 -0800196TEST_P(PeerConnectionDataChannelTest, SctpContentAndTransportNameSetCorrectly) {
Steve Antonda6c0952017-10-23 11:41:54 -0700197 auto caller = CreatePeerConnection();
198 auto callee = CreatePeerConnection();
199
200 // Initially these fields should be empty.
201 EXPECT_FALSE(caller->sctp_content_name());
202 EXPECT_FALSE(caller->sctp_transport_name());
203
204 // Create offer with audio/video/data.
205 // Default bundle policy is "balanced", so data should be using its own
206 // transport.
207 caller->AddAudioTrack("a");
208 caller->AddVideoTrack("v");
209 caller->pc()->CreateDataChannel("dc", nullptr);
Steve Antondbf9d032018-01-19 15:23:40 -0800210
211 auto offer = caller->CreateOffer();
212 const auto& offer_contents = offer->description()->contents();
213 ASSERT_EQ(cricket::MEDIA_TYPE_AUDIO,
214 offer_contents[0].media_description()->type());
215 std::string audio_mid = offer_contents[0].name;
216 ASSERT_EQ(cricket::MEDIA_TYPE_DATA,
217 offer_contents[2].media_description()->type());
218 std::string data_mid = offer_contents[2].name;
219
220 ASSERT_TRUE(
221 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
222 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
Steve Antonda6c0952017-10-23 11:41:54 -0700223
224 ASSERT_TRUE(caller->sctp_content_name());
Steve Antondbf9d032018-01-19 15:23:40 -0800225 EXPECT_EQ(data_mid, *caller->sctp_content_name());
Steve Antonda6c0952017-10-23 11:41:54 -0700226 ASSERT_TRUE(caller->sctp_transport_name());
Steve Antondbf9d032018-01-19 15:23:40 -0800227 EXPECT_EQ(data_mid, *caller->sctp_transport_name());
Steve Antonda6c0952017-10-23 11:41:54 -0700228
229 // Create answer that finishes BUNDLE negotiation, which means everything
230 // should be bundled on the first transport (audio).
231 RTCOfferAnswerOptions options;
232 options.use_rtp_mux = true;
233 ASSERT_TRUE(
234 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
235
236 ASSERT_TRUE(caller->sctp_content_name());
Steve Antondbf9d032018-01-19 15:23:40 -0800237 EXPECT_EQ(data_mid, *caller->sctp_content_name());
Steve Antonda6c0952017-10-23 11:41:54 -0700238 ASSERT_TRUE(caller->sctp_transport_name());
Steve Antondbf9d032018-01-19 15:23:40 -0800239 EXPECT_EQ(audio_mid, *caller->sctp_transport_name());
Steve Antonda6c0952017-10-23 11:41:54 -0700240}
241
Steve Antondbf9d032018-01-19 15:23:40 -0800242TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700243 CreateOfferWithNoDataChannelsGivesNoDataSection) {
244 auto caller = CreatePeerConnection();
245 auto offer = caller->CreateOffer();
246
247 EXPECT_FALSE(offer->description()->GetContentByName(cricket::CN_DATA));
248 EXPECT_FALSE(offer->description()->GetTransportInfoByName(cricket::CN_DATA));
249}
250
Steve Antondbf9d032018-01-19 15:23:40 -0800251TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700252 CreateAnswerWithRemoteSctpDataChannelIncludesDataSection) {
253 auto caller = CreatePeerConnectionWithDataChannel();
254 auto callee = CreatePeerConnection();
255
256 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
257
258 auto answer = callee->CreateAnswer();
259 ASSERT_TRUE(answer);
Steve Antondbf9d032018-01-19 15:23:40 -0800260 auto* data_content = cricket::GetFirstDataContent(answer->description());
Steve Antonda6c0952017-10-23 11:41:54 -0700261 ASSERT_TRUE(data_content);
262 EXPECT_FALSE(data_content->rejected);
Steve Antondbf9d032018-01-19 15:23:40 -0800263 EXPECT_TRUE(
264 answer->description()->GetTransportInfoByName(data_content->name));
Steve Antonda6c0952017-10-23 11:41:54 -0700265}
266
Steve Antondbf9d032018-01-19 15:23:40 -0800267TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700268 CreateDataChannelWithDtlsDisabledSucceeds) {
269 RTCConfiguration config;
270 config.enable_dtls_srtp.emplace(false);
271 auto caller = CreatePeerConnection();
272
273 EXPECT_TRUE(caller->pc()->CreateDataChannel("dc", nullptr));
274}
275
Steve Antondbf9d032018-01-19 15:23:40 -0800276TEST_P(PeerConnectionDataChannelTest, CreateDataChannelWithSctpDisabledFails) {
Steve Antonda6c0952017-10-23 11:41:54 -0700277 PeerConnectionFactoryInterface::Options options;
278 options.disable_sctp_data_channels = true;
279 auto caller = CreatePeerConnection(RTCConfiguration(), options);
280
281 EXPECT_FALSE(caller->pc()->CreateDataChannel("dc", nullptr));
282}
283
284// Test that if a callee has SCTP disabled and receives an offer with an SCTP
285// data channel, the data section is rejected and no SCTP transport is created
286// on the callee.
Steve Antondbf9d032018-01-19 15:23:40 -0800287TEST_P(PeerConnectionDataChannelTest,
Steve Antonda6c0952017-10-23 11:41:54 -0700288 DataSectionRejectedIfCalleeHasSctpDisabled) {
289 auto caller = CreatePeerConnectionWithDataChannel();
290 PeerConnectionFactoryInterface::Options options;
291 options.disable_sctp_data_channels = true;
292 auto callee = CreatePeerConnection(RTCConfiguration(), options);
293
294 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
295
296 EXPECT_FALSE(callee->sctp_transport_factory()->last_fake_sctp_transport());
297
298 auto answer = callee->CreateAnswer();
Steve Antondbf9d032018-01-19 15:23:40 -0800299 auto* data_content = cricket::GetFirstDataContent(answer->description());
Steve Antonda6c0952017-10-23 11:41:54 -0700300 ASSERT_TRUE(data_content);
301 EXPECT_TRUE(data_content->rejected);
302}
303
Steve Antondbf9d032018-01-19 15:23:40 -0800304TEST_P(PeerConnectionDataChannelTest, SctpPortPropagatedFromSdpToTransport) {
Steve Antonda6c0952017-10-23 11:41:54 -0700305 constexpr int kNewSendPort = 9998;
306 constexpr int kNewRecvPort = 7775;
307
308 auto caller = CreatePeerConnectionWithDataChannel();
309 auto callee = CreatePeerConnectionWithDataChannel();
310
311 auto offer = caller->CreateOffer();
312 ChangeSctpPortOnDescription(offer->description(), kNewSendPort);
313 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
314
315 auto answer = callee->CreateAnswer();
316 ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
317 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
318
319 auto* callee_transport =
320 callee->sctp_transport_factory()->last_fake_sctp_transport();
321 ASSERT_TRUE(callee_transport);
322 EXPECT_EQ(kNewSendPort, callee_transport->remote_port());
323 EXPECT_EQ(kNewRecvPort, callee_transport->local_port());
324}
325
Steve Antondbf9d032018-01-19 15:23:40 -0800326INSTANTIATE_TEST_CASE_P(PeerConnectionDataChannelTest,
327 PeerConnectionDataChannelTest,
328 Values(SdpSemantics::kPlanB,
329 SdpSemantics::kUnifiedPlan));
330
Steve Antonda6c0952017-10-23 11:41:54 -0700331} // namespace webrtc