blob: e6d6ac15502165b2e5cd463b46c2b9d454872cd6 [file] [log] [blame]
Steve Antonf1c6db12017-10-13 11:13:35 -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 "p2p/base/fakeportallocator.h"
12#include "p2p/base/teststunserver.h"
13#include "p2p/client/basicportallocator.h"
14#include "pc/mediasession.h"
Qingsi Wange1692722017-11-29 13:27:20 -080015#include "pc/peerconnection.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070016#include "pc/peerconnectionwrapper.h"
17#include "pc/sdputils.h"
18#ifdef WEBRTC_ANDROID
19#include "pc/test/androidtestinitializer.h"
20#endif
Karl Wiberg918f50c2018-07-05 11:40:33 +020021#include "absl/memory/memory.h"
Karl Wiberg1b0eae32017-10-17 14:48:54 +020022#include "api/audio_codecs/builtin_audio_decoder_factory.h"
23#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Qingsi Wange1692722017-11-29 13:27:20 -080024#include "api/peerconnectionproxy.h"
Yves Gerey2e00abc2018-10-05 15:39:24 +020025#include "api/umametrics.h"
Anders Carlsson67537952018-05-03 11:28:29 +020026#include "api/video_codecs/builtin_video_decoder_factory.h"
27#include "api/video_codecs/builtin_video_encoder_factory.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070028#include "pc/test/fakeaudiocapturemodule.h"
29#include "rtc_base/fakenetwork.h"
30#include "rtc_base/gunit.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020031#include "rtc_base/strings/string_builder.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070032#include "rtc_base/virtualsocketserver.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020033#include "system_wrappers/include/metrics.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070034
35namespace webrtc {
36
37using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
38using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
39using rtc::SocketAddress;
Steve Anton46d926a2018-01-23 10:23:06 -080040using ::testing::Combine;
Steve Antonf1c6db12017-10-13 11:13:35 -070041using ::testing::Values;
42
43constexpr int kIceCandidatesTimeout = 10000;
44
Steve Anton46d926a2018-01-23 10:23:06 -080045class PeerConnectionWrapperForIceTest : public PeerConnectionWrapper {
Steve Antonf1c6db12017-10-13 11:13:35 -070046 public:
47 using PeerConnectionWrapper::PeerConnectionWrapper;
48
49 // Adds a new ICE candidate to the first transport.
50 bool AddIceCandidate(cricket::Candidate* candidate) {
51 RTC_DCHECK(pc()->remote_description());
52 const auto* desc = pc()->remote_description()->description();
53 RTC_DCHECK(desc->contents().size() > 0);
54 const auto& first_content = desc->contents()[0];
55 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -070056 std::unique_ptr<IceCandidateInterface> jsep_candidate =
57 CreateIceCandidate(first_content.name, 0, *candidate);
58 return pc()->AddIceCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -070059 }
60
61 // Returns ICE candidates from the remote session description.
62 std::vector<const IceCandidateInterface*>
63 GetIceCandidatesFromRemoteDescription() {
64 const SessionDescriptionInterface* sdesc = pc()->remote_description();
65 RTC_DCHECK(sdesc);
66 std::vector<const IceCandidateInterface*> candidates;
67 for (size_t mline_index = 0; mline_index < sdesc->number_of_mediasections();
68 mline_index++) {
69 const auto* candidate_collection = sdesc->candidates(mline_index);
70 for (size_t i = 0; i < candidate_collection->count(); i++) {
71 candidates.push_back(candidate_collection->at(i));
72 }
73 }
74 return candidates;
75 }
76
77 rtc::FakeNetworkManager* network() { return network_; }
78
79 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
80
81 private:
82 rtc::FakeNetworkManager* network_;
83};
84
Steve Anton46d926a2018-01-23 10:23:06 -080085class PeerConnectionIceBaseTest : public ::testing::Test {
Steve Antonf1c6db12017-10-13 11:13:35 -070086 protected:
Steve Anton46d926a2018-01-23 10:23:06 -080087 typedef std::unique_ptr<PeerConnectionWrapperForIceTest> WrapperPtr;
Steve Antonf1c6db12017-10-13 11:13:35 -070088
Steve Anton46d926a2018-01-23 10:23:06 -080089 explicit PeerConnectionIceBaseTest(SdpSemantics sdp_semantics)
90 : vss_(new rtc::VirtualSocketServer()),
91 main_(vss_.get()),
92 sdp_semantics_(sdp_semantics) {
Steve Antonf1c6db12017-10-13 11:13:35 -070093#ifdef WEBRTC_ANDROID
94 InitializeAndroidObjects();
95#endif
96 pc_factory_ = CreatePeerConnectionFactory(
97 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Anders Carlsson67537952018-05-03 11:28:29 +020098 rtc::scoped_refptr<AudioDeviceModule>(FakeAudioCaptureModule::Create()),
99 CreateBuiltinAudioEncoderFactory(), CreateBuiltinAudioDecoderFactory(),
100 CreateBuiltinVideoEncoderFactory(), CreateBuiltinVideoDecoderFactory(),
101 nullptr /* audio_mixer */, nullptr /* audio_processing */);
Steve Antonf1c6db12017-10-13 11:13:35 -0700102 }
103
104 WrapperPtr CreatePeerConnection() {
105 return CreatePeerConnection(RTCConfiguration());
106 }
107
108 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
109 auto* fake_network = NewFakeNetwork();
110 auto port_allocator =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200111 absl::make_unique<cricket::BasicPortAllocator>(fake_network);
Steve Antonf1c6db12017-10-13 11:13:35 -0700112 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
113 cricket::PORTALLOCATOR_DISABLE_RELAY);
114 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
Steve Anton46d926a2018-01-23 10:23:06 -0800115 RTCConfiguration modified_config = config;
116 modified_config.sdp_semantics = sdp_semantics_;
Karl Wiberg918f50c2018-07-05 11:40:33 +0200117 auto observer = absl::make_unique<MockPeerConnectionObserver>();
Steve Antonf1c6db12017-10-13 11:13:35 -0700118 auto pc = pc_factory_->CreatePeerConnection(
Steve Anton46d926a2018-01-23 10:23:06 -0800119 modified_config, std::move(port_allocator), nullptr, observer.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700120 if (!pc) {
121 return nullptr;
122 }
123
Karl Wiberg918f50c2018-07-05 11:40:33 +0200124 auto wrapper = absl::make_unique<PeerConnectionWrapperForIceTest>(
Steve Antonf1c6db12017-10-13 11:13:35 -0700125 pc_factory_, pc, std::move(observer));
126 wrapper->set_network(fake_network);
127 return wrapper;
128 }
129
130 // Accepts the same arguments as CreatePeerConnection and adds default audio
131 // and video tracks.
132 template <typename... Args>
133 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
134 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
135 if (!wrapper) {
136 return nullptr;
137 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700138 wrapper->AddAudioTrack("a");
139 wrapper->AddVideoTrack("v");
Steve Antonf1c6db12017-10-13 11:13:35 -0700140 return wrapper;
141 }
142
143 cricket::Candidate CreateLocalUdpCandidate(
144 const rtc::SocketAddress& address) {
145 cricket::Candidate candidate;
146 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
147 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
148 candidate.set_address(address);
149 candidate.set_type(cricket::LOCAL_PORT_TYPE);
150 return candidate;
151 }
152
153 // Remove all ICE ufrag/pwd lines from the given session description.
154 void RemoveIceUfragPwd(SessionDescriptionInterface* sdesc) {
155 SetIceUfragPwd(sdesc, "", "");
156 }
157
158 // Sets all ICE ufrag/pwds on the given session description.
159 void SetIceUfragPwd(SessionDescriptionInterface* sdesc,
160 const std::string& ufrag,
161 const std::string& pwd) {
162 auto* desc = sdesc->description();
163 for (const auto& content : desc->contents()) {
164 auto* transport_info = desc->GetTransportInfoByName(content.name);
165 transport_info->description.ice_ufrag = ufrag;
166 transport_info->description.ice_pwd = pwd;
167 }
168 }
169
Qingsi Wange1692722017-11-29 13:27:20 -0800170 // Set ICE mode on the given session description.
171 void SetIceMode(SessionDescriptionInterface* sdesc,
172 const cricket::IceMode ice_mode) {
173 auto* desc = sdesc->description();
174 for (const auto& content : desc->contents()) {
175 auto* transport_info = desc->GetTransportInfoByName(content.name);
176 transport_info->description.ice_mode = ice_mode;
177 }
178 }
179
Steve Antonf1c6db12017-10-13 11:13:35 -0700180 cricket::TransportDescription* GetFirstTransportDescription(
181 SessionDescriptionInterface* sdesc) {
182 auto* desc = sdesc->description();
183 RTC_DCHECK(desc->contents().size() > 0);
184 auto* transport_info =
185 desc->GetTransportInfoByName(desc->contents()[0].name);
186 RTC_DCHECK(transport_info);
187 return &transport_info->description;
188 }
189
190 const cricket::TransportDescription* GetFirstTransportDescription(
191 const SessionDescriptionInterface* sdesc) {
192 auto* desc = sdesc->description();
193 RTC_DCHECK(desc->contents().size() > 0);
194 auto* transport_info =
195 desc->GetTransportInfoByName(desc->contents()[0].name);
196 RTC_DCHECK(transport_info);
197 return &transport_info->description;
198 }
199
Qingsi Wange1692722017-11-29 13:27:20 -0800200 // TODO(qingsi): Rewrite this method in terms of the standard IceTransport
201 // after it is implemented.
202 cricket::IceRole GetIceRole(const WrapperPtr& pc_wrapper_ptr) {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100203 auto* pc_proxy =
204 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
205 pc_wrapper_ptr->pc());
206 PeerConnection* pc = static_cast<PeerConnection*>(pc_proxy->internal());
Steve Antonb8867112018-02-13 10:07:54 -0800207 for (auto transceiver : pc->GetTransceiversInternal()) {
Steve Anton69470252018-02-09 11:43:08 -0800208 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Steve Anton46d926a2018-01-23 10:23:06 -0800209 cricket::BaseChannel* channel = transceiver->internal()->channel();
210 if (channel) {
Zhi Huange830e682018-03-30 10:48:35 -0700211 auto dtls_transport = static_cast<cricket::DtlsTransportInternal*>(
212 channel->rtp_packet_transport());
213 return dtls_transport->ice_transport()->GetIceRole();
Steve Anton46d926a2018-01-23 10:23:06 -0800214 }
215 }
216 }
217 RTC_NOTREACHED();
218 return cricket::ICEROLE_UNKNOWN;
Qingsi Wange1692722017-11-29 13:27:20 -0800219 }
220
Steve Antonf1c6db12017-10-13 11:13:35 -0700221 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
222 SessionDescriptionInterface* sdesc) {
223 auto* desc = sdesc->description();
224 RTC_DCHECK(desc->contents().size() > 0);
225 const auto& first_content = desc->contents()[0];
226 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -0700227 std::unique_ptr<IceCandidateInterface> jsep_candidate =
228 CreateIceCandidate(first_content.name, 0, *candidate);
229 return sdesc->AddCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700230 }
231
232 rtc::FakeNetworkManager* NewFakeNetwork() {
233 // The PeerConnection's port allocator is tied to the PeerConnection's
234 // lifetime and expects the underlying NetworkManager to outlive it. That
235 // prevents us from having the PeerConnectionWrapper own the fake network.
236 // Therefore, the test fixture will own all the fake networks even though
237 // tests should access the fake network through the PeerConnectionWrapper.
238 auto* fake_network = new rtc::FakeNetworkManager();
239 fake_networks_.emplace_back(fake_network);
240 return fake_network;
241 }
242
243 std::unique_ptr<rtc::VirtualSocketServer> vss_;
244 rtc::AutoSocketServerThread main_;
245 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
246 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton46d926a2018-01-23 10:23:06 -0800247 const SdpSemantics sdp_semantics_;
248};
249
250class PeerConnectionIceTest
251 : public PeerConnectionIceBaseTest,
252 public ::testing::WithParamInterface<SdpSemantics> {
253 protected:
Harald Alvestrand76829d72018-07-18 23:24:36 +0200254 PeerConnectionIceTest() : PeerConnectionIceBaseTest(GetParam()) {
255 webrtc::metrics::Reset();
256 }
Steve Antonf1c6db12017-10-13 11:13:35 -0700257};
258
259::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
260 const char* b_expr,
261 const cricket::Candidate& a,
262 const cricket::Candidate& b) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200263 rtc::StringBuilder failure_info;
Steve Antonf1c6db12017-10-13 11:13:35 -0700264 if (a.component() != b.component()) {
265 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
266 }
267 if (a.protocol() != b.protocol()) {
268 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
269 }
270 if (a.address() != b.address()) {
271 failure_info << "\naddress: " << a.address().ToString()
272 << " != " << b.address().ToString();
273 }
274 if (a.type() != b.type()) {
275 failure_info << "\ntype: " << a.type() << " != " << b.type();
276 }
277 std::string failure_info_str = failure_info.str();
278 if (failure_info_str.empty()) {
279 return ::testing::AssertionSuccess();
280 } else {
281 return ::testing::AssertionFailure()
282 << a_expr << " and " << b_expr << " are not equal"
283 << failure_info_str;
284 }
285}
286
Steve Anton46d926a2018-01-23 10:23:06 -0800287TEST_P(PeerConnectionIceTest, OfferContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700288 const SocketAddress kLocalAddress("1.1.1.1", 0);
289
290 auto caller = CreatePeerConnectionWithAudioVideo();
291 caller->network()->AddInterface(kLocalAddress);
292
293 // Start ICE candidate gathering by setting the local offer.
294 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
295
296 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
297
298 auto offer = caller->CreateOffer();
299 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
300 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
301 offer->candidates(0)->count());
302 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
303 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
304 offer->candidates(1)->count());
305}
306
Steve Anton46d926a2018-01-23 10:23:06 -0800307TEST_P(PeerConnectionIceTest, AnswerContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700308 const SocketAddress kCallerAddress("1.1.1.1", 0);
309
310 auto caller = CreatePeerConnectionWithAudioVideo();
311 auto callee = CreatePeerConnectionWithAudioVideo();
312 caller->network()->AddInterface(kCallerAddress);
313
314 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
315 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
316
317 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
318
Steve Antondffead82018-02-06 10:31:29 -0800319 auto* answer = callee->pc()->local_description();
Steve Antonf1c6db12017-10-13 11:13:35 -0700320 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
321 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
322 answer->candidates(0)->count());
323 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
324 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
325 answer->candidates(1)->count());
326}
327
Steve Anton46d926a2018-01-23 10:23:06 -0800328TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700329 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
330 const SocketAddress kCallerAddress("1.1.1.1", 1111);
331
332 auto caller = CreatePeerConnectionWithAudioVideo();
333 auto callee = CreatePeerConnectionWithAudioVideo();
334
335 auto offer = caller->CreateOfferAndSetAsLocal();
336 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
337 AddCandidateToFirstTransport(&candidate, offer.get());
338
339 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
340 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
341 ASSERT_EQ(1u, remote_candidates.size());
342 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
343 remote_candidates[0]->candidate());
344}
345
Steve Anton46d926a2018-01-23 10:23:06 -0800346TEST_P(PeerConnectionIceTest, SetLocalDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700347 auto caller = CreatePeerConnectionWithAudioVideo();
348
349 auto offer = caller->CreateOffer();
350 RemoveIceUfragPwd(offer.get());
351
352 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
353}
354
Steve Anton46d926a2018-01-23 10:23:06 -0800355TEST_P(PeerConnectionIceTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700356 auto caller = CreatePeerConnectionWithAudioVideo();
357 auto callee = CreatePeerConnectionWithAudioVideo();
358
359 auto offer = caller->CreateOfferAndSetAsLocal();
360 RemoveIceUfragPwd(offer.get());
361
362 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
363}
364
Steve Antonf764cf42018-05-01 14:32:17 -0700365// Test that doing an offer/answer exchange with no transport (i.e., no data
366// channel or media) results in the ICE connection state staying at New.
367TEST_P(PeerConnectionIceTest,
368 OfferAnswerWithNoTransportsDoesNotChangeIceConnectionState) {
369 auto caller = CreatePeerConnection();
370 auto callee = CreatePeerConnection();
371
372 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
373
374 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
375 caller->pc()->ice_connection_state());
376 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
377 callee->pc()->ice_connection_state());
378}
379
Steve Antonf1c6db12017-10-13 11:13:35 -0700380// The following group tests that ICE candidates are not generated before
381// SetLocalDescription is called on a PeerConnection.
382
Steve Anton46d926a2018-01-23 10:23:06 -0800383TEST_P(PeerConnectionIceTest, NoIceCandidatesBeforeSetLocalDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700384 const SocketAddress kLocalAddress("1.1.1.1", 0);
385
386 auto caller = CreatePeerConnectionWithAudioVideo();
387 caller->network()->AddInterface(kLocalAddress);
388
389 // Pump for 1 second and verify that no candidates are generated.
390 rtc::Thread::Current()->ProcessMessages(1000);
391
392 EXPECT_EQ(0u, caller->observer()->candidates_.size());
393}
Steve Anton46d926a2018-01-23 10:23:06 -0800394TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700395 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
396 const SocketAddress kCallerAddress("1.1.1.1", 1111);
397
398 auto caller = CreatePeerConnectionWithAudioVideo();
399 auto callee = CreatePeerConnectionWithAudioVideo();
400 caller->network()->AddInterface(kCallerAddress);
401
402 auto offer = caller->CreateOfferAndSetAsLocal();
403 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
404 AddCandidateToFirstTransport(&candidate, offer.get());
405 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
406
407 // Pump for 1 second and verify that no candidates are generated.
408 rtc::Thread::Current()->ProcessMessages(1000);
409
410 EXPECT_EQ(0u, callee->observer()->candidates_.size());
411}
412
Steve Anton46d926a2018-01-23 10:23:06 -0800413TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenRemoteDescriptionNotSet) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700414 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
415
416 auto caller = CreatePeerConnectionWithAudioVideo();
417 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton27ab0e52018-07-23 15:11:53 -0700418 std::unique_ptr<IceCandidateInterface> jsep_candidate =
419 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
Steve Antonf1c6db12017-10-13 11:13:35 -0700420
Steve Anton27ab0e52018-07-23 15:11:53 -0700421 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700422
423 caller->CreateOfferAndSetAsLocal();
424
Steve Anton27ab0e52018-07-23 15:11:53 -0700425 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Harald Alvestrand76829d72018-07-18 23:24:36 +0200426 EXPECT_EQ(
427 2, webrtc::metrics::NumSamples("WebRTC.PeerConnection.AddIceCandidate"));
428 EXPECT_EQ(
429 2, webrtc::metrics::NumEvents("WebRTC.PeerConnection.AddIceCandidate",
430 kAddIceCandidateFailNoRemoteDescription));
Steve Antonf1c6db12017-10-13 11:13:35 -0700431}
432
Steve Antonc79268f2018-04-24 09:54:10 -0700433TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenPeerConnectionClosed) {
434 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
435
436 auto caller = CreatePeerConnectionWithAudioVideo();
437 auto callee = CreatePeerConnectionWithAudioVideo();
438
439 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
440
441 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
442 auto* audio_content = cricket::GetFirstAudioContent(
443 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700444 std::unique_ptr<IceCandidateInterface> jsep_candidate =
445 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700446
447 caller->pc()->Close();
448
Steve Anton27ab0e52018-07-23 15:11:53 -0700449 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700450}
451
Steve Anton46d926a2018-01-23 10:23:06 -0800452TEST_P(PeerConnectionIceTest, DuplicateIceCandidateIgnoredWhenAdded) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700453 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
454
455 auto caller = CreatePeerConnectionWithAudioVideo();
456 auto callee = CreatePeerConnectionWithAudioVideo();
457
458 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
459 ASSERT_TRUE(
460 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
461
462 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
463 caller->AddIceCandidate(&candidate);
464 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
465 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
466}
467
Steve Anton46d926a2018-01-23 10:23:06 -0800468TEST_P(PeerConnectionIceTest,
Steve Antonc79268f2018-04-24 09:54:10 -0700469 CannotRemoveIceCandidatesWhenPeerConnectionClosed) {
470 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
471
472 auto caller = CreatePeerConnectionWithAudioVideo();
473 auto callee = CreatePeerConnectionWithAudioVideo();
474
475 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
476
477 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
478 auto* audio_content = cricket::GetFirstAudioContent(
479 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700480 std::unique_ptr<IceCandidateInterface> ice_candidate =
481 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700482
Steve Anton27ab0e52018-07-23 15:11:53 -0700483 ASSERT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700484
485 caller->pc()->Close();
486
487 EXPECT_FALSE(caller->pc()->RemoveIceCandidates({candidate}));
488}
489
490TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700491 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
492 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
493
494 auto caller = CreatePeerConnectionWithAudioVideo();
495 auto callee = CreatePeerConnectionWithAudioVideo();
496
497 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
498 ASSERT_TRUE(
499 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
500
501 // |candidate.transport_name()| is empty.
502 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton46d926a2018-01-23 10:23:06 -0800503 auto* audio_content = cricket::GetFirstAudioContent(
504 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700505 std::unique_ptr<IceCandidateInterface> ice_candidate =
506 CreateIceCandidate(audio_content->name, 0, candidate);
507 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700508 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
509}
510
Steve Anton46d926a2018-01-23 10:23:06 -0800511TEST_P(PeerConnectionIceTest, RemoveCandidateRemovesFromRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700512 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
513
514 auto caller = CreatePeerConnectionWithAudioVideo();
515 auto callee = CreatePeerConnectionWithAudioVideo();
516
517 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
518 ASSERT_TRUE(
519 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
520
521 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
522 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
523 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
524 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
525}
526
527// Test that if a candidate is added via AddIceCandidate and via an updated
528// remote description, then both candidates appear in the stored remote
529// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800530TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700531 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
532 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
533 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
534
535 auto caller = CreatePeerConnectionWithAudioVideo();
536 auto callee = CreatePeerConnectionWithAudioVideo();
537
538 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
539 ASSERT_TRUE(
540 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
541
542 // Add one candidate via |AddIceCandidate|.
543 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
544 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
545
546 // Add the second candidate via a reoffer.
547 auto offer = caller->CreateOffer();
548 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
549 AddCandidateToFirstTransport(&candidate2, offer.get());
550
551 // Expect both candidates to appear in the callee's remote description.
552 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
553 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
554}
555
556// The follow test verifies that SetLocal/RemoteDescription fails when an offer
557// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
558// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
559// pwd must be 22-256 characters and ufrag must be 4-256 characters.
Steve Anton46d926a2018-01-23 10:23:06 -0800560TEST_P(PeerConnectionIceTest, VerifyUfragPwdLength) {
Yves Gerey665174f2018-06-19 15:03:05 +0200561 auto set_local_description_with_ufrag_pwd_length = [this](int ufrag_len,
562 int pwd_len) {
563 auto pc = CreatePeerConnectionWithAudioVideo();
564 auto offer = pc->CreateOffer();
565 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
566 std::string(pwd_len, 'x'));
567 return pc->SetLocalDescription(std::move(offer));
568 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700569
Yves Gerey665174f2018-06-19 15:03:05 +0200570 auto set_remote_description_with_ufrag_pwd_length = [this](int ufrag_len,
571 int pwd_len) {
572 auto pc = CreatePeerConnectionWithAudioVideo();
573 auto offer = pc->CreateOffer();
574 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
575 std::string(pwd_len, 'x'));
576 return pc->SetRemoteDescription(std::move(offer));
577 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700578
579 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
580 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
581 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
582 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
583 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
584 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
585 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
586 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
587 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
588 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
589 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
590 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
591}
592
593::testing::AssertionResult AssertIpInCandidates(
594 const char* address_expr,
595 const char* candidates_expr,
596 const SocketAddress& address,
597 const std::vector<IceCandidateInterface*> candidates) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200598 rtc::StringBuilder candidate_hosts;
Steve Antonf1c6db12017-10-13 11:13:35 -0700599 for (const auto* candidate : candidates) {
600 const auto& candidate_ip = candidate->candidate().address().ipaddr();
601 if (candidate_ip == address.ipaddr()) {
602 return ::testing::AssertionSuccess();
603 }
Jonas Olssonabbe8412018-04-03 13:40:05 +0200604 candidate_hosts << "\n" << candidate_ip.ToString();
Steve Antonf1c6db12017-10-13 11:13:35 -0700605 }
606 return ::testing::AssertionFailure()
607 << address_expr << " (host " << address.HostAsURIString()
608 << ") not in " << candidates_expr
609 << " which have the following address hosts:" << candidate_hosts.str();
610}
611
Steve Anton46d926a2018-01-23 10:23:06 -0800612TEST_P(PeerConnectionIceTest, CandidatesGeneratedForEachLocalInterface) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700613 const SocketAddress kLocalAddress1("1.1.1.1", 0);
614 const SocketAddress kLocalAddress2("2.2.2.2", 0);
615
616 auto caller = CreatePeerConnectionWithAudioVideo();
617 caller->network()->AddInterface(kLocalAddress1);
618 caller->network()->AddInterface(kLocalAddress2);
619
620 caller->CreateOfferAndSetAsLocal();
621 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
622
623 auto candidates = caller->observer()->GetCandidatesByMline(0);
624 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
625 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
626}
627
Steve Anton46d926a2018-01-23 10:23:06 -0800628TEST_P(PeerConnectionIceTest, TrickledSingleCandidateAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700629 const SocketAddress kCallerAddress("1.1.1.1", 1111);
630
631 auto caller = CreatePeerConnectionWithAudioVideo();
632 auto callee = CreatePeerConnectionWithAudioVideo();
633
634 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
635
636 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
637 callee->AddIceCandidate(&candidate);
638 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
639 ASSERT_EQ(1u, candidates.size());
640 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
641 candidates[0]->candidate());
642}
643
Steve Anton46d926a2018-01-23 10:23:06 -0800644TEST_P(PeerConnectionIceTest, TwoTrickledCandidatesAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700645 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
646 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
647
648 auto caller = CreatePeerConnectionWithAudioVideo();
649 auto callee = CreatePeerConnectionWithAudioVideo();
650
651 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
652 ASSERT_TRUE(
653 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
654
655 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
656 caller->AddIceCandidate(&candidate1);
657
658 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
659 caller->AddIceCandidate(&candidate2);
660
661 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
662 ASSERT_EQ(2u, candidates.size());
663 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
664 candidates[0]->candidate());
665 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
666 candidates[1]->candidate());
667}
668
Steve Anton46d926a2018-01-23 10:23:06 -0800669TEST_P(PeerConnectionIceTest, LocalDescriptionUpdatedWhenContinualGathering) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700670 const SocketAddress kLocalAddress("1.1.1.1", 0);
671
672 RTCConfiguration config;
673 config.continual_gathering_policy =
674 PeerConnectionInterface::GATHER_CONTINUALLY;
675 auto caller = CreatePeerConnectionWithAudioVideo(config);
676 caller->network()->AddInterface(kLocalAddress);
677
678 // Start ICE candidate gathering by setting the local offer.
679 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
680
681 // Since we're using continual gathering, we won't get "gathering done".
682 EXPECT_TRUE_WAIT(
683 caller->pc()->local_description()->candidates(0)->count() > 0,
684 kIceCandidatesTimeout);
685}
686
687// Test that when continual gathering is enabled, and a network interface goes
688// down, the candidate is signaled as removed and removed from the local
689// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800690TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700691 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
692 const SocketAddress kLocalAddress("1.1.1.1", 0);
693
694 RTCConfiguration config;
695 config.continual_gathering_policy =
696 PeerConnectionInterface::GATHER_CONTINUALLY;
697 auto caller = CreatePeerConnectionWithAudioVideo(config);
698 caller->network()->AddInterface(kLocalAddress);
699
700 // Start ICE candidate gathering by setting the local offer.
701 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
702
703 EXPECT_TRUE_WAIT(
704 caller->pc()->local_description()->candidates(0)->count() > 0,
705 kIceCandidatesTimeout);
706
707 // Remove the only network interface, causing the PeerConnection to signal
708 // the removal of all candidates derived from this interface.
709 caller->network()->RemoveInterface(kLocalAddress);
710
711 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
712 kIceCandidatesTimeout);
713 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
714}
715
Steve Anton46d926a2018-01-23 10:23:06 -0800716TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700717 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
718 const SocketAddress kLocalAddress("1.1.1.1", 0);
719
720 RTCConfiguration config;
721 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
722 auto caller = CreatePeerConnectionWithAudioVideo(config);
723 caller->network()->AddInterface(kLocalAddress);
724
725 // Start ICE candidate gathering by setting the local offer.
726 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
727
728 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
729
730 caller->network()->RemoveInterface(kLocalAddress);
731
732 // Verify that the local candidates are not removed;
733 rtc::Thread::Current()->ProcessMessages(1000);
734 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
735}
736
737// The following group tests that when an offer includes a new ufrag or pwd
738// (indicating an ICE restart) the old candidates are removed and new candidates
739// added to the remote description.
740
Steve Anton46d926a2018-01-23 10:23:06 -0800741TEST_P(PeerConnectionIceTest, IceRestartOfferClearsExistingCandidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700742 const SocketAddress kCallerAddress("1.1.1.1", 1111);
743
744 auto caller = CreatePeerConnectionWithAudioVideo();
745 auto callee = CreatePeerConnectionWithAudioVideo();
746
747 auto offer = caller->CreateOffer();
748 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
749 AddCandidateToFirstTransport(&candidate, offer.get());
750
751 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
752
753 RTCOfferAnswerOptions options;
754 options.ice_restart = true;
755 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer(options)));
756
757 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
758}
Steve Anton46d926a2018-01-23 10:23:06 -0800759TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700760 IceRestartOfferCandidateReplacesExistingCandidate) {
761 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
762 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
763
764 auto caller = CreatePeerConnectionWithAudioVideo();
765 auto callee = CreatePeerConnectionWithAudioVideo();
766
767 auto offer = caller->CreateOffer();
768 cricket::Candidate old_candidate =
769 CreateLocalUdpCandidate(kFirstCallerAddress);
770 AddCandidateToFirstTransport(&old_candidate, offer.get());
771
772 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
773
774 RTCOfferAnswerOptions options;
775 options.ice_restart = true;
776 auto restart_offer = caller->CreateOffer(options);
777 cricket::Candidate new_candidate =
778 CreateLocalUdpCandidate(kRestartedCallerAddress);
779 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
780
781 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
782
783 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
784 ASSERT_EQ(1u, remote_candidates.size());
785 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
786 remote_candidates[0]->candidate());
787}
788
789// Test that if there is not an ICE restart (i.e., nothing changes), then the
790// answer to a later offer should have the same ufrag/pwd as the first answer.
Steve Anton46d926a2018-01-23 10:23:06 -0800791TEST_P(PeerConnectionIceTest, LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700792 auto caller = CreatePeerConnectionWithAudioVideo();
793 auto callee = CreatePeerConnectionWithAudioVideo();
794
795 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
796 ASSERT_TRUE(
797 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
798
799 // Re-offer.
800 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
801
802 auto answer = callee->CreateAnswer();
803 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
804 auto* local_transport_desc =
805 GetFirstTransportDescription(callee->pc()->local_description());
806
807 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
808 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
809}
810
811// The following parameterized test verifies that if an offer is sent with a
812// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
813// other side has initiated an ICE restart and generate a new ufrag and pwd.
814// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
815// a=ice-pwd attributes compared to the previous SDP from the peer, it
816// indicates that ICE is restarting for this media stream."
817
Steve Anton46d926a2018-01-23 10:23:06 -0800818class PeerConnectionIceUfragPwdAnswerTest
819 : public PeerConnectionIceBaseTest,
820 public ::testing::WithParamInterface<
821 std::tuple<SdpSemantics, std::tuple<bool, bool>>> {
Steve Antonf1c6db12017-10-13 11:13:35 -0700822 protected:
Steve Anton46d926a2018-01-23 10:23:06 -0800823 PeerConnectionIceUfragPwdAnswerTest()
824 : PeerConnectionIceBaseTest(std::get<0>(GetParam())) {
825 auto param = std::get<1>(GetParam());
826 offer_new_ufrag_ = std::get<0>(param);
827 offer_new_pwd_ = std::get<1>(param);
Steve Antonf1c6db12017-10-13 11:13:35 -0700828 }
829
830 bool offer_new_ufrag_;
831 bool offer_new_pwd_;
832};
833
Steve Anton46d926a2018-01-23 10:23:06 -0800834TEST_P(PeerConnectionIceUfragPwdAnswerTest, TestIncludedInAnswer) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700835 auto caller = CreatePeerConnectionWithAudioVideo();
836 auto callee = CreatePeerConnectionWithAudioVideo();
837
838 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
839 ASSERT_TRUE(
840 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
841
842 auto offer = caller->CreateOffer();
843 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
844 if (offer_new_ufrag_) {
845 offer_transport_desc->ice_ufrag += "_new";
846 }
847 if (offer_new_pwd_) {
848 offer_transport_desc->ice_pwd += "_new";
849 }
850
851 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
852
853 auto answer = callee->CreateAnswer();
854 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
855 auto* local_transport_desc =
856 GetFirstTransportDescription(callee->pc()->local_description());
857
858 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
859 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
860}
861
862INSTANTIATE_TEST_CASE_P(
Steve Anton46d926a2018-01-23 10:23:06 -0800863 PeerConnectionIceTest,
864 PeerConnectionIceUfragPwdAnswerTest,
865 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
866 Values(std::make_pair(true, true), // Both changed.
867 std::make_pair(true, false), // Only ufrag changed.
868 std::make_pair(false, true)))); // Only pwd changed.
Steve Antonf1c6db12017-10-13 11:13:35 -0700869
870// Test that if an ICE restart is offered on one media section, then the answer
871// will only change ICE ufrag/pwd for that section and keep the other sections
872// the same.
873// Note that this only works if we have disabled BUNDLE, otherwise all media
874// sections will share the same transport.
Steve Anton46d926a2018-01-23 10:23:06 -0800875TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700876 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
877 auto caller = CreatePeerConnectionWithAudioVideo();
878 auto callee = CreatePeerConnectionWithAudioVideo();
879
880 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
881 ASSERT_TRUE(
882 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
883
884 RTCOfferAnswerOptions disable_bundle_options;
885 disable_bundle_options.use_rtp_mux = false;
886
887 auto offer = caller->CreateOffer(disable_bundle_options);
888
889 // Signal ICE restart on the first media section.
890 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
891 offer_transport_desc->ice_ufrag += "_new";
892 offer_transport_desc->ice_pwd += "_new";
893
894 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
895
896 auto answer = callee->CreateAnswer(disable_bundle_options);
897 const auto& answer_transports = answer->description()->transport_infos();
898 const auto& local_transports =
899 callee->pc()->local_description()->description()->transport_infos();
900
901 EXPECT_NE(answer_transports[0].description.ice_ufrag,
902 local_transports[0].description.ice_ufrag);
903 EXPECT_NE(answer_transports[0].description.ice_pwd,
904 local_transports[0].description.ice_pwd);
905 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
906 local_transports[1].description.ice_ufrag);
907 EXPECT_EQ(answer_transports[1].description.ice_pwd,
908 local_transports[1].description.ice_pwd);
909}
910
Qingsi Wange1692722017-11-29 13:27:20 -0800911// Test that when the initial offerer (caller) uses the lite implementation of
912// ICE and the callee uses the full implementation, the caller takes the
913// CONTROLLED role and the callee takes the CONTROLLING role. This is specified
914// in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -0800915TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -0800916 OfferFromLiteIceControlledAndAnswerFromFullIceControlling) {
917 auto caller = CreatePeerConnectionWithAudioVideo();
918 auto callee = CreatePeerConnectionWithAudioVideo();
919
920 auto offer = caller->CreateOffer();
921 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
922 ASSERT_TRUE(
923 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
924 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
925
926 auto answer = callee->CreateAnswer();
927 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_FULL);
928 ASSERT_TRUE(
929 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
930 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
931
932 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(caller));
933 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(callee));
934}
935
936// Test that when the caller and the callee both use the lite implementation of
937// ICE, the initial offerer (caller) takes the CONTROLLING role and the callee
938// takes the CONTROLLED role. This is specified in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -0800939TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -0800940 OfferFromLiteIceControllingAndAnswerFromLiteIceControlled) {
941 auto caller = CreatePeerConnectionWithAudioVideo();
942 auto callee = CreatePeerConnectionWithAudioVideo();
943
944 auto offer = caller->CreateOffer();
945 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
946 ASSERT_TRUE(
947 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
948 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
949
950 auto answer = callee->CreateAnswer();
951 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_LITE);
952 ASSERT_TRUE(
953 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
954 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
955
956 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(caller));
957 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(callee));
958}
959
Steve Anton46d926a2018-01-23 10:23:06 -0800960INSTANTIATE_TEST_CASE_P(PeerConnectionIceTest,
961 PeerConnectionIceTest,
962 Values(SdpSemantics::kPlanB,
963 SdpSemantics::kUnifiedPlan));
964
Qingsi Wang4ff54432018-03-01 18:25:20 -0800965class PeerConnectionIceConfigTest : public testing::Test {
966 protected:
967 void SetUp() override {
968 pc_factory_ = CreatePeerConnectionFactory(
969 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
970 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
Anders Carlsson67537952018-05-03 11:28:29 +0200971 CreateBuiltinAudioDecoderFactory(), CreateBuiltinVideoEncoderFactory(),
972 CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
973 nullptr /* audio_processing */);
Qingsi Wang4ff54432018-03-01 18:25:20 -0800974 }
975 void CreatePeerConnection(const RTCConfiguration& config) {
976 std::unique_ptr<cricket::FakePortAllocator> port_allocator(
977 new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr));
978 port_allocator_ = port_allocator.get();
979 rtc::scoped_refptr<PeerConnectionInterface> pc(
Niels Möllerf06f9232018-08-07 12:32:18 +0200980 pc_factory_->CreatePeerConnection(config, std::move(port_allocator),
981 nullptr /* cert_generator */,
982 &observer_));
Qingsi Wang4ff54432018-03-01 18:25:20 -0800983 EXPECT_TRUE(pc.get());
984 pc_ = std::move(pc.get());
985 }
986
987 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_ = nullptr;
988 rtc::scoped_refptr<PeerConnectionInterface> pc_ = nullptr;
989 cricket::FakePortAllocator* port_allocator_ = nullptr;
990
991 MockPeerConnectionObserver observer_;
992};
993
994TEST_F(PeerConnectionIceConfigTest, SetStunCandidateKeepaliveInterval) {
995 RTCConfiguration config;
996 config.stun_candidate_keepalive_interval = 123;
997 config.ice_candidate_pool_size = 1;
998 CreatePeerConnection(config);
999 ASSERT_NE(port_allocator_, nullptr);
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001000 absl::optional<int> actual_stun_keepalive_interval =
Qingsi Wang4ff54432018-03-01 18:25:20 -08001001 port_allocator_->stun_candidate_keepalive_interval();
1002 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 123);
1003 config.stun_candidate_keepalive_interval = 321;
1004 RTCError error;
1005 pc_->SetConfiguration(config, &error);
1006 actual_stun_keepalive_interval =
1007 port_allocator_->stun_candidate_keepalive_interval();
1008 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 321);
1009}
1010
Steve Antonf1c6db12017-10-13 11:13:35 -07001011} // namespace webrtc