blob: 088001841de9d6b0155538008eb69e3ac5fde181 [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"
15#include "pc/peerconnectionwrapper.h"
16#include "pc/sdputils.h"
17#ifdef WEBRTC_ANDROID
18#include "pc/test/androidtestinitializer.h"
19#endif
Karl Wiberg1b0eae32017-10-17 14:48:54 +020020#include "api/audio_codecs/builtin_audio_decoder_factory.h"
21#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070022#include "pc/test/fakeaudiocapturemodule.h"
23#include "rtc_base/fakenetwork.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 rtc::SocketAddress;
33using ::testing::Values;
34
35constexpr int kIceCandidatesTimeout = 10000;
36
37class PeerConnectionWrapperForIceUnitTest : public PeerConnectionWrapper {
38 public:
39 using PeerConnectionWrapper::PeerConnectionWrapper;
40
41 // Adds a new ICE candidate to the first transport.
42 bool AddIceCandidate(cricket::Candidate* candidate) {
43 RTC_DCHECK(pc()->remote_description());
44 const auto* desc = pc()->remote_description()->description();
45 RTC_DCHECK(desc->contents().size() > 0);
46 const auto& first_content = desc->contents()[0];
47 candidate->set_transport_name(first_content.name);
48 JsepIceCandidate jsep_candidate(first_content.name, 0, *candidate);
49 return pc()->AddIceCandidate(&jsep_candidate);
50 }
51
52 // Returns ICE candidates from the remote session description.
53 std::vector<const IceCandidateInterface*>
54 GetIceCandidatesFromRemoteDescription() {
55 const SessionDescriptionInterface* sdesc = pc()->remote_description();
56 RTC_DCHECK(sdesc);
57 std::vector<const IceCandidateInterface*> candidates;
58 for (size_t mline_index = 0; mline_index < sdesc->number_of_mediasections();
59 mline_index++) {
60 const auto* candidate_collection = sdesc->candidates(mline_index);
61 for (size_t i = 0; i < candidate_collection->count(); i++) {
62 candidates.push_back(candidate_collection->at(i));
63 }
64 }
65 return candidates;
66 }
67
68 rtc::FakeNetworkManager* network() { return network_; }
69
70 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
71
72 private:
73 rtc::FakeNetworkManager* network_;
74};
75
76class PeerConnectionIceUnitTest : public ::testing::Test {
77 protected:
78 typedef std::unique_ptr<PeerConnectionWrapperForIceUnitTest> WrapperPtr;
79
80 PeerConnectionIceUnitTest()
81 : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
82#ifdef WEBRTC_ANDROID
83 InitializeAndroidObjects();
84#endif
85 pc_factory_ = CreatePeerConnectionFactory(
86 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Karl Wiberg1b0eae32017-10-17 14:48:54 +020087 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
88 CreateBuiltinAudioDecoderFactory(), nullptr, nullptr);
Steve Antonf1c6db12017-10-13 11:13:35 -070089 }
90
91 WrapperPtr CreatePeerConnection() {
92 return CreatePeerConnection(RTCConfiguration());
93 }
94
95 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
96 auto* fake_network = NewFakeNetwork();
97 auto port_allocator =
98 rtc::MakeUnique<cricket::BasicPortAllocator>(fake_network);
99 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
100 cricket::PORTALLOCATOR_DISABLE_RELAY);
101 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
102 auto observer = rtc::MakeUnique<MockPeerConnectionObserver>();
103 auto pc = pc_factory_->CreatePeerConnection(
104 config, std::move(port_allocator), nullptr, observer.get());
105 if (!pc) {
106 return nullptr;
107 }
108
109 auto wrapper = rtc::MakeUnique<PeerConnectionWrapperForIceUnitTest>(
110 pc_factory_, pc, std::move(observer));
111 wrapper->set_network(fake_network);
112 return wrapper;
113 }
114
115 // Accepts the same arguments as CreatePeerConnection and adds default audio
116 // and video tracks.
117 template <typename... Args>
118 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
119 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
120 if (!wrapper) {
121 return nullptr;
122 }
123 wrapper->AddAudioVideoStream("s", "a", "v");
124 return wrapper;
125 }
126
127 cricket::Candidate CreateLocalUdpCandidate(
128 const rtc::SocketAddress& address) {
129 cricket::Candidate candidate;
130 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
131 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
132 candidate.set_address(address);
133 candidate.set_type(cricket::LOCAL_PORT_TYPE);
134 return candidate;
135 }
136
137 // Remove all ICE ufrag/pwd lines from the given session description.
138 void RemoveIceUfragPwd(SessionDescriptionInterface* sdesc) {
139 SetIceUfragPwd(sdesc, "", "");
140 }
141
142 // Sets all ICE ufrag/pwds on the given session description.
143 void SetIceUfragPwd(SessionDescriptionInterface* sdesc,
144 const std::string& ufrag,
145 const std::string& pwd) {
146 auto* desc = sdesc->description();
147 for (const auto& content : desc->contents()) {
148 auto* transport_info = desc->GetTransportInfoByName(content.name);
149 transport_info->description.ice_ufrag = ufrag;
150 transport_info->description.ice_pwd = pwd;
151 }
152 }
153
154 cricket::TransportDescription* GetFirstTransportDescription(
155 SessionDescriptionInterface* sdesc) {
156 auto* desc = sdesc->description();
157 RTC_DCHECK(desc->contents().size() > 0);
158 auto* transport_info =
159 desc->GetTransportInfoByName(desc->contents()[0].name);
160 RTC_DCHECK(transport_info);
161 return &transport_info->description;
162 }
163
164 const cricket::TransportDescription* GetFirstTransportDescription(
165 const SessionDescriptionInterface* sdesc) {
166 auto* desc = sdesc->description();
167 RTC_DCHECK(desc->contents().size() > 0);
168 auto* transport_info =
169 desc->GetTransportInfoByName(desc->contents()[0].name);
170 RTC_DCHECK(transport_info);
171 return &transport_info->description;
172 }
173
174 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
175 SessionDescriptionInterface* sdesc) {
176 auto* desc = sdesc->description();
177 RTC_DCHECK(desc->contents().size() > 0);
178 const auto& first_content = desc->contents()[0];
179 candidate->set_transport_name(first_content.name);
180 JsepIceCandidate jsep_candidate(first_content.name, 0, *candidate);
181 return sdesc->AddCandidate(&jsep_candidate);
182 }
183
184 rtc::FakeNetworkManager* NewFakeNetwork() {
185 // The PeerConnection's port allocator is tied to the PeerConnection's
186 // lifetime and expects the underlying NetworkManager to outlive it. That
187 // prevents us from having the PeerConnectionWrapper own the fake network.
188 // Therefore, the test fixture will own all the fake networks even though
189 // tests should access the fake network through the PeerConnectionWrapper.
190 auto* fake_network = new rtc::FakeNetworkManager();
191 fake_networks_.emplace_back(fake_network);
192 return fake_network;
193 }
194
195 std::unique_ptr<rtc::VirtualSocketServer> vss_;
196 rtc::AutoSocketServerThread main_;
197 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
198 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
199};
200
201::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
202 const char* b_expr,
203 const cricket::Candidate& a,
204 const cricket::Candidate& b) {
205 std::stringstream failure_info;
206 if (a.component() != b.component()) {
207 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
208 }
209 if (a.protocol() != b.protocol()) {
210 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
211 }
212 if (a.address() != b.address()) {
213 failure_info << "\naddress: " << a.address().ToString()
214 << " != " << b.address().ToString();
215 }
216 if (a.type() != b.type()) {
217 failure_info << "\ntype: " << a.type() << " != " << b.type();
218 }
219 std::string failure_info_str = failure_info.str();
220 if (failure_info_str.empty()) {
221 return ::testing::AssertionSuccess();
222 } else {
223 return ::testing::AssertionFailure()
224 << a_expr << " and " << b_expr << " are not equal"
225 << failure_info_str;
226 }
227}
228
229TEST_F(PeerConnectionIceUnitTest, OfferContainsGatheredCandidates) {
230 const SocketAddress kLocalAddress("1.1.1.1", 0);
231
232 auto caller = CreatePeerConnectionWithAudioVideo();
233 caller->network()->AddInterface(kLocalAddress);
234
235 // Start ICE candidate gathering by setting the local offer.
236 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
237
238 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
239
240 auto offer = caller->CreateOffer();
241 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
242 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
243 offer->candidates(0)->count());
244 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
245 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
246 offer->candidates(1)->count());
247}
248
249TEST_F(PeerConnectionIceUnitTest, AnswerContainsGatheredCandidates) {
250 const SocketAddress kCallerAddress("1.1.1.1", 0);
251
252 auto caller = CreatePeerConnectionWithAudioVideo();
253 auto callee = CreatePeerConnectionWithAudioVideo();
254 caller->network()->AddInterface(kCallerAddress);
255
256 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
257 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
258
259 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
260
261 auto answer = callee->CreateAnswer();
262 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
263 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
264 answer->candidates(0)->count());
265 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
266 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
267 answer->candidates(1)->count());
268}
269
270TEST_F(PeerConnectionIceUnitTest,
271 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
272 const SocketAddress kCallerAddress("1.1.1.1", 1111);
273
274 auto caller = CreatePeerConnectionWithAudioVideo();
275 auto callee = CreatePeerConnectionWithAudioVideo();
276
277 auto offer = caller->CreateOfferAndSetAsLocal();
278 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
279 AddCandidateToFirstTransport(&candidate, offer.get());
280
281 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
282 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
283 ASSERT_EQ(1u, remote_candidates.size());
284 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
285 remote_candidates[0]->candidate());
286}
287
288TEST_F(PeerConnectionIceUnitTest, SetLocalDescriptionFailsIfNoIceCredentials) {
289 auto caller = CreatePeerConnectionWithAudioVideo();
290
291 auto offer = caller->CreateOffer();
292 RemoveIceUfragPwd(offer.get());
293
294 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
295}
296
297TEST_F(PeerConnectionIceUnitTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
298 auto caller = CreatePeerConnectionWithAudioVideo();
299 auto callee = CreatePeerConnectionWithAudioVideo();
300
301 auto offer = caller->CreateOfferAndSetAsLocal();
302 RemoveIceUfragPwd(offer.get());
303
304 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
305}
306
307// The following group tests that ICE candidates are not generated before
308// SetLocalDescription is called on a PeerConnection.
309
310TEST_F(PeerConnectionIceUnitTest, NoIceCandidatesBeforeSetLocalDescription) {
311 const SocketAddress kLocalAddress("1.1.1.1", 0);
312
313 auto caller = CreatePeerConnectionWithAudioVideo();
314 caller->network()->AddInterface(kLocalAddress);
315
316 // Pump for 1 second and verify that no candidates are generated.
317 rtc::Thread::Current()->ProcessMessages(1000);
318
319 EXPECT_EQ(0u, caller->observer()->candidates_.size());
320}
321TEST_F(PeerConnectionIceUnitTest,
322 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
323 const SocketAddress kCallerAddress("1.1.1.1", 1111);
324
325 auto caller = CreatePeerConnectionWithAudioVideo();
326 auto callee = CreatePeerConnectionWithAudioVideo();
327 caller->network()->AddInterface(kCallerAddress);
328
329 auto offer = caller->CreateOfferAndSetAsLocal();
330 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
331 AddCandidateToFirstTransport(&candidate, offer.get());
332 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
333
334 // Pump for 1 second and verify that no candidates are generated.
335 rtc::Thread::Current()->ProcessMessages(1000);
336
337 EXPECT_EQ(0u, callee->observer()->candidates_.size());
338}
339
340TEST_F(PeerConnectionIceUnitTest,
341 CannotAddCandidateWhenRemoteDescriptionNotSet) {
342 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
343
344 auto caller = CreatePeerConnectionWithAudioVideo();
345 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
346 JsepIceCandidate jsep_candidate(cricket::CN_AUDIO, 0, candidate);
347
348 EXPECT_FALSE(caller->pc()->AddIceCandidate(&jsep_candidate));
349
350 caller->CreateOfferAndSetAsLocal();
351
352 EXPECT_FALSE(caller->pc()->AddIceCandidate(&jsep_candidate));
353}
354
355TEST_F(PeerConnectionIceUnitTest, DuplicateIceCandidateIgnoredWhenAdded) {
356 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
357
358 auto caller = CreatePeerConnectionWithAudioVideo();
359 auto callee = CreatePeerConnectionWithAudioVideo();
360
361 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
362 ASSERT_TRUE(
363 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
364
365 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
366 caller->AddIceCandidate(&candidate);
367 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
368 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
369}
370
371TEST_F(PeerConnectionIceUnitTest,
372 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
373 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
374
375 auto caller = CreatePeerConnectionWithAudioVideo();
376 auto callee = CreatePeerConnectionWithAudioVideo();
377
378 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
379 ASSERT_TRUE(
380 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
381
382 // |candidate.transport_name()| is empty.
383 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
384 JsepIceCandidate ice_candidate(cricket::CN_AUDIO, 0, candidate);
385 EXPECT_TRUE(caller->pc()->AddIceCandidate(&ice_candidate));
386 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
387}
388
389TEST_F(PeerConnectionIceUnitTest, RemoveCandidateRemovesFromRemoteDescription) {
390 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
391
392 auto caller = CreatePeerConnectionWithAudioVideo();
393 auto callee = CreatePeerConnectionWithAudioVideo();
394
395 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
396 ASSERT_TRUE(
397 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
398
399 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
400 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
401 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
402 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
403}
404
405// Test that if a candidate is added via AddIceCandidate and via an updated
406// remote description, then both candidates appear in the stored remote
407// description.
408TEST_F(PeerConnectionIceUnitTest,
409 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
410 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
411 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
412
413 auto caller = CreatePeerConnectionWithAudioVideo();
414 auto callee = CreatePeerConnectionWithAudioVideo();
415
416 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
417 ASSERT_TRUE(
418 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
419
420 // Add one candidate via |AddIceCandidate|.
421 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
422 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
423
424 // Add the second candidate via a reoffer.
425 auto offer = caller->CreateOffer();
426 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
427 AddCandidateToFirstTransport(&candidate2, offer.get());
428
429 // Expect both candidates to appear in the callee's remote description.
430 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
431 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
432}
433
434// The follow test verifies that SetLocal/RemoteDescription fails when an offer
435// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
436// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
437// pwd must be 22-256 characters and ufrag must be 4-256 characters.
438TEST_F(PeerConnectionIceUnitTest, VerifyUfragPwdLength) {
439 auto caller = CreatePeerConnectionWithAudioVideo();
440 auto callee = CreatePeerConnectionWithAudioVideo();
441
442 auto set_local_description_with_ufrag_pwd_length =
443 [this, &caller](int ufrag_len, int pwd_len) {
444 auto offer = caller->CreateOffer();
445 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
446 std::string(pwd_len, 'x'));
447 return caller->SetLocalDescription(std::move(offer));
448 };
449
450 auto set_remote_description_with_ufrag_pwd_length =
451 [this, &caller, &callee](int ufrag_len, int pwd_len) {
452 auto offer = caller->CreateOffer();
453 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
454 std::string(pwd_len, 'x'));
455 return callee->SetRemoteDescription(std::move(offer));
456 };
457
458 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
459 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
460 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
461 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
462 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
463 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
464 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
465 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
466 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
467 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
468 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
469 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
470}
471
472::testing::AssertionResult AssertIpInCandidates(
473 const char* address_expr,
474 const char* candidates_expr,
475 const SocketAddress& address,
476 const std::vector<IceCandidateInterface*> candidates) {
477 std::stringstream candidate_hosts;
478 for (const auto* candidate : candidates) {
479 const auto& candidate_ip = candidate->candidate().address().ipaddr();
480 if (candidate_ip == address.ipaddr()) {
481 return ::testing::AssertionSuccess();
482 }
483 candidate_hosts << "\n" << candidate_ip;
484 }
485 return ::testing::AssertionFailure()
486 << address_expr << " (host " << address.HostAsURIString()
487 << ") not in " << candidates_expr
488 << " which have the following address hosts:" << candidate_hosts.str();
489}
490
491TEST_F(PeerConnectionIceUnitTest, CandidatesGeneratedForEachLocalInterface) {
492 const SocketAddress kLocalAddress1("1.1.1.1", 0);
493 const SocketAddress kLocalAddress2("2.2.2.2", 0);
494
495 auto caller = CreatePeerConnectionWithAudioVideo();
496 caller->network()->AddInterface(kLocalAddress1);
497 caller->network()->AddInterface(kLocalAddress2);
498
499 caller->CreateOfferAndSetAsLocal();
500 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
501
502 auto candidates = caller->observer()->GetCandidatesByMline(0);
503 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
504 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
505}
506
507TEST_F(PeerConnectionIceUnitTest,
508 TrickledSingleCandidateAddedToRemoteDescription) {
509 const SocketAddress kCallerAddress("1.1.1.1", 1111);
510
511 auto caller = CreatePeerConnectionWithAudioVideo();
512 auto callee = CreatePeerConnectionWithAudioVideo();
513
514 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
515
516 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
517 callee->AddIceCandidate(&candidate);
518 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
519 ASSERT_EQ(1u, candidates.size());
520 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
521 candidates[0]->candidate());
522}
523
524TEST_F(PeerConnectionIceUnitTest,
525 TwoTrickledCandidatesAddedToRemoteDescription) {
526 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
527 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
528
529 auto caller = CreatePeerConnectionWithAudioVideo();
530 auto callee = CreatePeerConnectionWithAudioVideo();
531
532 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
533 ASSERT_TRUE(
534 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
535
536 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
537 caller->AddIceCandidate(&candidate1);
538
539 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
540 caller->AddIceCandidate(&candidate2);
541
542 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
543 ASSERT_EQ(2u, candidates.size());
544 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
545 candidates[0]->candidate());
546 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
547 candidates[1]->candidate());
548}
549
550TEST_F(PeerConnectionIceUnitTest,
551 LocalDescriptionUpdatedWhenContinualGathering) {
552 const SocketAddress kLocalAddress("1.1.1.1", 0);
553
554 RTCConfiguration config;
555 config.continual_gathering_policy =
556 PeerConnectionInterface::GATHER_CONTINUALLY;
557 auto caller = CreatePeerConnectionWithAudioVideo(config);
558 caller->network()->AddInterface(kLocalAddress);
559
560 // Start ICE candidate gathering by setting the local offer.
561 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
562
563 // Since we're using continual gathering, we won't get "gathering done".
564 EXPECT_TRUE_WAIT(
565 caller->pc()->local_description()->candidates(0)->count() > 0,
566 kIceCandidatesTimeout);
567}
568
569// Test that when continual gathering is enabled, and a network interface goes
570// down, the candidate is signaled as removed and removed from the local
571// description.
572TEST_F(PeerConnectionIceUnitTest,
573 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
574 const SocketAddress kLocalAddress("1.1.1.1", 0);
575
576 RTCConfiguration config;
577 config.continual_gathering_policy =
578 PeerConnectionInterface::GATHER_CONTINUALLY;
579 auto caller = CreatePeerConnectionWithAudioVideo(config);
580 caller->network()->AddInterface(kLocalAddress);
581
582 // Start ICE candidate gathering by setting the local offer.
583 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
584
585 EXPECT_TRUE_WAIT(
586 caller->pc()->local_description()->candidates(0)->count() > 0,
587 kIceCandidatesTimeout);
588
589 // Remove the only network interface, causing the PeerConnection to signal
590 // the removal of all candidates derived from this interface.
591 caller->network()->RemoveInterface(kLocalAddress);
592
593 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
594 kIceCandidatesTimeout);
595 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
596}
597
598TEST_F(PeerConnectionIceUnitTest,
599 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
600 const SocketAddress kLocalAddress("1.1.1.1", 0);
601
602 RTCConfiguration config;
603 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
604 auto caller = CreatePeerConnectionWithAudioVideo(config);
605 caller->network()->AddInterface(kLocalAddress);
606
607 // Start ICE candidate gathering by setting the local offer.
608 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
609
610 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
611
612 caller->network()->RemoveInterface(kLocalAddress);
613
614 // Verify that the local candidates are not removed;
615 rtc::Thread::Current()->ProcessMessages(1000);
616 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
617}
618
619// The following group tests that when an offer includes a new ufrag or pwd
620// (indicating an ICE restart) the old candidates are removed and new candidates
621// added to the remote description.
622
623TEST_F(PeerConnectionIceUnitTest, IceRestartOfferClearsExistingCandidate) {
624 const SocketAddress kCallerAddress("1.1.1.1", 1111);
625
626 auto caller = CreatePeerConnectionWithAudioVideo();
627 auto callee = CreatePeerConnectionWithAudioVideo();
628
629 auto offer = caller->CreateOffer();
630 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
631 AddCandidateToFirstTransport(&candidate, offer.get());
632
633 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
634
635 RTCOfferAnswerOptions options;
636 options.ice_restart = true;
637 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer(options)));
638
639 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
640}
641TEST_F(PeerConnectionIceUnitTest,
642 IceRestartOfferCandidateReplacesExistingCandidate) {
643 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
644 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
645
646 auto caller = CreatePeerConnectionWithAudioVideo();
647 auto callee = CreatePeerConnectionWithAudioVideo();
648
649 auto offer = caller->CreateOffer();
650 cricket::Candidate old_candidate =
651 CreateLocalUdpCandidate(kFirstCallerAddress);
652 AddCandidateToFirstTransport(&old_candidate, offer.get());
653
654 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
655
656 RTCOfferAnswerOptions options;
657 options.ice_restart = true;
658 auto restart_offer = caller->CreateOffer(options);
659 cricket::Candidate new_candidate =
660 CreateLocalUdpCandidate(kRestartedCallerAddress);
661 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
662
663 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
664
665 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
666 ASSERT_EQ(1u, remote_candidates.size());
667 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
668 remote_candidates[0]->candidate());
669}
670
671// Test that if there is not an ICE restart (i.e., nothing changes), then the
672// answer to a later offer should have the same ufrag/pwd as the first answer.
673TEST_F(PeerConnectionIceUnitTest,
674 LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
675 auto caller = CreatePeerConnectionWithAudioVideo();
676 auto callee = CreatePeerConnectionWithAudioVideo();
677
678 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
679 ASSERT_TRUE(
680 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
681
682 // Re-offer.
683 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
684
685 auto answer = callee->CreateAnswer();
686 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
687 auto* local_transport_desc =
688 GetFirstTransportDescription(callee->pc()->local_description());
689
690 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
691 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
692}
693
694// The following parameterized test verifies that if an offer is sent with a
695// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
696// other side has initiated an ICE restart and generate a new ufrag and pwd.
697// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
698// a=ice-pwd attributes compared to the previous SDP from the peer, it
699// indicates that ICE is restarting for this media stream."
700
701class PeerConnectionIceUfragPwdAnswerUnitTest
702 : public PeerConnectionIceUnitTest,
703 public ::testing::WithParamInterface<std::pair<bool, bool>> {
704 protected:
705 PeerConnectionIceUfragPwdAnswerUnitTest() {
706 offer_new_ufrag_ = GetParam().first;
707 offer_new_pwd_ = GetParam().second;
708 }
709
710 bool offer_new_ufrag_;
711 bool offer_new_pwd_;
712};
713
714TEST_P(PeerConnectionIceUfragPwdAnswerUnitTest, TestIncludedInAnswer) {
715 auto caller = CreatePeerConnectionWithAudioVideo();
716 auto callee = CreatePeerConnectionWithAudioVideo();
717
718 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
719 ASSERT_TRUE(
720 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
721
722 auto offer = caller->CreateOffer();
723 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
724 if (offer_new_ufrag_) {
725 offer_transport_desc->ice_ufrag += "_new";
726 }
727 if (offer_new_pwd_) {
728 offer_transport_desc->ice_pwd += "_new";
729 }
730
731 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
732
733 auto answer = callee->CreateAnswer();
734 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
735 auto* local_transport_desc =
736 GetFirstTransportDescription(callee->pc()->local_description());
737
738 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
739 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
740}
741
742INSTANTIATE_TEST_CASE_P(
743 PeerConnectionIceUnitTest,
744 PeerConnectionIceUfragPwdAnswerUnitTest,
745 Values(std::make_pair(true, true), // Both changed.
746 std::make_pair(true, false), // Only ufrag changed.
747 std::make_pair(false, true))); // Only pwd changed.
748
749// Test that if an ICE restart is offered on one media section, then the answer
750// will only change ICE ufrag/pwd for that section and keep the other sections
751// the same.
752// Note that this only works if we have disabled BUNDLE, otherwise all media
753// sections will share the same transport.
754TEST_F(PeerConnectionIceUnitTest,
755 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
756 auto caller = CreatePeerConnectionWithAudioVideo();
757 auto callee = CreatePeerConnectionWithAudioVideo();
758
759 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
760 ASSERT_TRUE(
761 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
762
763 RTCOfferAnswerOptions disable_bundle_options;
764 disable_bundle_options.use_rtp_mux = false;
765
766 auto offer = caller->CreateOffer(disable_bundle_options);
767
768 // Signal ICE restart on the first media section.
769 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
770 offer_transport_desc->ice_ufrag += "_new";
771 offer_transport_desc->ice_pwd += "_new";
772
773 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
774
775 auto answer = callee->CreateAnswer(disable_bundle_options);
776 const auto& answer_transports = answer->description()->transport_infos();
777 const auto& local_transports =
778 callee->pc()->local_description()->description()->transport_infos();
779
780 EXPECT_NE(answer_transports[0].description.ice_ufrag,
781 local_transports[0].description.ice_ufrag);
782 EXPECT_NE(answer_transports[0].description.ice_pwd,
783 local_transports[0].description.ice_pwd);
784 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
785 local_transports[1].description.ice_ufrag);
786 EXPECT_EQ(answer_transports[1].description.ice_pwd,
787 local_transports[1].description.ice_pwd);
788}
789
790} // namespace webrtc