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