blob: 918544cc276adadd3c702c46935ae410c064b352 [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"
19#ifdef WEBRTC_ANDROID
20#include "pc/test/androidtestinitializer.h"
21#endif
22#include "pc/test/fakesctptransport.h"
23#include "rtc_base/gunit.h"
24#include "rtc_base/ptr_util.h"
25#include "rtc_base/virtualsocketserver.h"
26
27namespace webrtc {
28
29using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
30using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
31using ::testing::Values;
32
33class PeerConnectionFactoryForDataChannelTest
34 : public rtc::RefCountedObject<PeerConnectionFactory> {
35 public:
36 PeerConnectionFactoryForDataChannelTest()
37 : rtc::RefCountedObject<PeerConnectionFactory>(
38 rtc::Thread::Current(),
39 rtc::Thread::Current(),
40 rtc::Thread::Current(),
41 rtc::MakeUnique<cricket::FakeMediaEngine>(),
42 CreateCallFactory(),
43 nullptr) {}
44
45 std::unique_ptr<cricket::SctpTransportInternalFactory>
46 CreateSctpTransportInternalFactory() {
47 auto factory = rtc::MakeUnique<FakeSctpTransportFactory>();
48 last_fake_sctp_transport_factory_ = factory.get();
49 return factory;
50 }
51
52 FakeSctpTransportFactory* last_fake_sctp_transport_factory_ = nullptr;
53};
54
55class PeerConnectionWrapperForDataChannelTest : public PeerConnectionWrapper {
56 public:
57 using PeerConnectionWrapper::PeerConnectionWrapper;
58
59 FakeSctpTransportFactory* sctp_transport_factory() {
60 return sctp_transport_factory_;
61 }
62
63 void set_sctp_transport_factory(
64 FakeSctpTransportFactory* sctp_transport_factory) {
65 sctp_transport_factory_ = sctp_transport_factory;
66 }
67
68 rtc::Optional<std::string> sctp_content_name() {
69 return GetInternalPeerConnection()->sctp_content_name();
70 }
71
72 rtc::Optional<std::string> sctp_transport_name() {
73 return GetInternalPeerConnection()->sctp_transport_name();
74 }
75
76 PeerConnection* GetInternalPeerConnection() {
77 auto* pci = reinterpret_cast<
78 PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(pc());
79 return reinterpret_cast<PeerConnection*>(pci->internal());
80 }
81
82 private:
83 FakeSctpTransportFactory* sctp_transport_factory_ = nullptr;
84};
85
86class PeerConnectionDataChannelTest : public ::testing::Test {
87 protected:
88 typedef std::unique_ptr<PeerConnectionWrapperForDataChannelTest> WrapperPtr;
89
90 PeerConnectionDataChannelTest()
91 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
92#ifdef WEBRTC_ANDROID
93 InitializeAndroidObjects();
94#endif
95 }
96
97 WrapperPtr CreatePeerConnection() {
98 return CreatePeerConnection(RTCConfiguration());
99 }
100
101 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
102 return CreatePeerConnection(config,
103 PeerConnectionFactoryInterface::Options());
104 }
105
106 WrapperPtr CreatePeerConnection(
107 const RTCConfiguration& config,
108 const PeerConnectionFactoryInterface::Options factory_options) {
109 rtc::scoped_refptr<PeerConnectionFactoryForDataChannelTest> pc_factory(
110 new PeerConnectionFactoryForDataChannelTest());
111 pc_factory->SetOptions(factory_options);
112 RTC_CHECK(pc_factory->Initialize());
113 auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
114 auto pc = pc_factory->CreatePeerConnection(config, nullptr, nullptr,
115 observer.get());
116 if (!pc) {
117 return nullptr;
118 }
119
120 auto wrapper = rtc::MakeUnique<PeerConnectionWrapperForDataChannelTest>(
121 pc_factory, pc, std::move(observer));
122 RTC_DCHECK(pc_factory->last_fake_sctp_transport_factory_);
123 wrapper->set_sctp_transport_factory(
124 pc_factory->last_fake_sctp_transport_factory_);
125 return wrapper;
126 }
127
128 // Accepts the same arguments as CreatePeerConnection and adds a default data
129 // channel.
130 template <typename... Args>
131 WrapperPtr CreatePeerConnectionWithDataChannel(Args&&... args) {
132 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
133 if (!wrapper) {
134 return nullptr;
135 }
136 EXPECT_TRUE(wrapper->pc()->CreateDataChannel("dc", nullptr));
137 return wrapper;
138 }
139
140 // Changes the SCTP data channel port on the given session description.
141 void ChangeSctpPortOnDescription(cricket::SessionDescription* desc,
142 int port) {
143 cricket::DataCodec sctp_codec(cricket::kGoogleSctpDataCodecPlType,
144 cricket::kGoogleSctpDataCodecName);
145 sctp_codec.SetParam(cricket::kCodecParamPort, port);
146
147 auto* data_content = cricket::GetFirstDataContent(desc);
148 RTC_DCHECK(data_content);
149 auto* data_desc = static_cast<cricket::DataContentDescription*>(
150 data_content->description);
151 data_desc->set_codecs({sctp_codec});
152 }
153
154 std::unique_ptr<rtc::VirtualSocketServer> vss_;
155 rtc::AutoSocketServerThread main_;
156};
157
158TEST_F(PeerConnectionDataChannelTest,
159 NoSctpTransportCreatedIfRtpDataChannelEnabled) {
160 RTCConfiguration config;
161 config.enable_rtp_data_channel = true;
162 auto caller = CreatePeerConnectionWithDataChannel(config);
163
164 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
165 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
166}
167
168TEST_F(PeerConnectionDataChannelTest,
169 RtpDataChannelCreatedEvenIfSctpAvailable) {
170 RTCConfiguration config;
171 config.enable_rtp_data_channel = true;
172 PeerConnectionFactoryInterface::Options options;
173 options.disable_sctp_data_channels = false;
174 auto caller = CreatePeerConnectionWithDataChannel(config, options);
175
176 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
177 EXPECT_FALSE(caller->sctp_transport_factory()->last_fake_sctp_transport());
178}
179
180// Test that sctp_content_name/sctp_transport_name (used for stats) are correct
181// before and after BUNDLE is negotiated.
182TEST_F(PeerConnectionDataChannelTest, SctpContentAndTransportNameSetCorrectly) {
183 auto caller = CreatePeerConnection();
184 auto callee = CreatePeerConnection();
185
186 // Initially these fields should be empty.
187 EXPECT_FALSE(caller->sctp_content_name());
188 EXPECT_FALSE(caller->sctp_transport_name());
189
190 // Create offer with audio/video/data.
191 // Default bundle policy is "balanced", so data should be using its own
192 // transport.
193 caller->AddAudioTrack("a");
194 caller->AddVideoTrack("v");
195 caller->pc()->CreateDataChannel("dc", nullptr);
196 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
197
198 ASSERT_TRUE(caller->sctp_content_name());
199 EXPECT_EQ(cricket::CN_DATA, *caller->sctp_content_name());
200 ASSERT_TRUE(caller->sctp_transport_name());
201 EXPECT_EQ(cricket::CN_DATA, *caller->sctp_transport_name());
202
203 // Create answer that finishes BUNDLE negotiation, which means everything
204 // should be bundled on the first transport (audio).
205 RTCOfferAnswerOptions options;
206 options.use_rtp_mux = true;
207 ASSERT_TRUE(
208 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
209
210 ASSERT_TRUE(caller->sctp_content_name());
211 EXPECT_EQ(cricket::CN_DATA, *caller->sctp_content_name());
212 ASSERT_TRUE(caller->sctp_transport_name());
213 EXPECT_EQ(cricket::CN_AUDIO, *caller->sctp_transport_name());
214}
215
216TEST_F(PeerConnectionDataChannelTest,
217 CreateOfferWithNoDataChannelsGivesNoDataSection) {
218 auto caller = CreatePeerConnection();
219 auto offer = caller->CreateOffer();
220
221 EXPECT_FALSE(offer->description()->GetContentByName(cricket::CN_DATA));
222 EXPECT_FALSE(offer->description()->GetTransportInfoByName(cricket::CN_DATA));
223}
224
225TEST_F(PeerConnectionDataChannelTest,
226 CreateAnswerWithRemoteSctpDataChannelIncludesDataSection) {
227 auto caller = CreatePeerConnectionWithDataChannel();
228 auto callee = CreatePeerConnection();
229
230 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
231
232 auto answer = callee->CreateAnswer();
233 ASSERT_TRUE(answer);
234 auto* data_content =
235 answer->description()->GetContentByName(cricket::CN_DATA);
236 ASSERT_TRUE(data_content);
237 EXPECT_FALSE(data_content->rejected);
238 EXPECT_TRUE(answer->description()->GetTransportInfoByName(cricket::CN_DATA));
239}
240
241TEST_F(PeerConnectionDataChannelTest,
242 CreateDataChannelWithDtlsDisabledSucceeds) {
243 RTCConfiguration config;
244 config.enable_dtls_srtp.emplace(false);
245 auto caller = CreatePeerConnection();
246
247 EXPECT_TRUE(caller->pc()->CreateDataChannel("dc", nullptr));
248}
249
250TEST_F(PeerConnectionDataChannelTest, CreateDataChannelWithSctpDisabledFails) {
251 PeerConnectionFactoryInterface::Options options;
252 options.disable_sctp_data_channels = true;
253 auto caller = CreatePeerConnection(RTCConfiguration(), options);
254
255 EXPECT_FALSE(caller->pc()->CreateDataChannel("dc", nullptr));
256}
257
258// Test that if a callee has SCTP disabled and receives an offer with an SCTP
259// data channel, the data section is rejected and no SCTP transport is created
260// on the callee.
261TEST_F(PeerConnectionDataChannelTest,
262 DataSectionRejectedIfCalleeHasSctpDisabled) {
263 auto caller = CreatePeerConnectionWithDataChannel();
264 PeerConnectionFactoryInterface::Options options;
265 options.disable_sctp_data_channels = true;
266 auto callee = CreatePeerConnection(RTCConfiguration(), options);
267
268 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
269
270 EXPECT_FALSE(callee->sctp_transport_factory()->last_fake_sctp_transport());
271
272 auto answer = callee->CreateAnswer();
273 auto* data_content =
274 answer->description()->GetContentByName(cricket::CN_DATA);
275 ASSERT_TRUE(data_content);
276 EXPECT_TRUE(data_content->rejected);
277}
278
279TEST_F(PeerConnectionDataChannelTest, SctpPortPropagatedFromSdpToTransport) {
280 constexpr int kNewSendPort = 9998;
281 constexpr int kNewRecvPort = 7775;
282
283 auto caller = CreatePeerConnectionWithDataChannel();
284 auto callee = CreatePeerConnectionWithDataChannel();
285
286 auto offer = caller->CreateOffer();
287 ChangeSctpPortOnDescription(offer->description(), kNewSendPort);
288 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
289
290 auto answer = callee->CreateAnswer();
291 ChangeSctpPortOnDescription(answer->description(), kNewRecvPort);
292 ASSERT_TRUE(callee->SetLocalDescription(std::move(answer)));
293
294 auto* callee_transport =
295 callee->sctp_transport_factory()->last_fake_sctp_transport();
296 ASSERT_TRUE(callee_transport);
297 EXPECT_EQ(kNewSendPort, callee_transport->remote_port());
298 EXPECT_EQ(kNewRecvPort, callee_transport->local_port());
299}
300
301} // namespace webrtc