blob: 52de1f65a43a9dc16d02f831851bdc497dbb1779 [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) {
190 auto* pc_proxy = reinterpret_cast<
191 PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
192 pc_wrapper_ptr->pc());
193 PeerConnection* pc =
194 reinterpret_cast<PeerConnection*>(pc_proxy->internal());
195 return pc->voice_channel()
196 ->rtp_dtls_transport()
197 ->ice_transport()
198 ->GetIceRole();
199 }
200
Steve Antonf1c6db12017-10-13 11:13:35 -0700201 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
202 SessionDescriptionInterface* sdesc) {
203 auto* desc = sdesc->description();
204 RTC_DCHECK(desc->contents().size() > 0);
205 const auto& first_content = desc->contents()[0];
206 candidate->set_transport_name(first_content.name);
207 JsepIceCandidate jsep_candidate(first_content.name, 0, *candidate);
208 return sdesc->AddCandidate(&jsep_candidate);
209 }
210
211 rtc::FakeNetworkManager* NewFakeNetwork() {
212 // The PeerConnection's port allocator is tied to the PeerConnection's
213 // lifetime and expects the underlying NetworkManager to outlive it. That
214 // prevents us from having the PeerConnectionWrapper own the fake network.
215 // Therefore, the test fixture will own all the fake networks even though
216 // tests should access the fake network through the PeerConnectionWrapper.
217 auto* fake_network = new rtc::FakeNetworkManager();
218 fake_networks_.emplace_back(fake_network);
219 return fake_network;
220 }
221
222 std::unique_ptr<rtc::VirtualSocketServer> vss_;
223 rtc::AutoSocketServerThread main_;
224 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
225 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
226};
227
228::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
229 const char* b_expr,
230 const cricket::Candidate& a,
231 const cricket::Candidate& b) {
232 std::stringstream failure_info;
233 if (a.component() != b.component()) {
234 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
235 }
236 if (a.protocol() != b.protocol()) {
237 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
238 }
239 if (a.address() != b.address()) {
240 failure_info << "\naddress: " << a.address().ToString()
241 << " != " << b.address().ToString();
242 }
243 if (a.type() != b.type()) {
244 failure_info << "\ntype: " << a.type() << " != " << b.type();
245 }
246 std::string failure_info_str = failure_info.str();
247 if (failure_info_str.empty()) {
248 return ::testing::AssertionSuccess();
249 } else {
250 return ::testing::AssertionFailure()
251 << a_expr << " and " << b_expr << " are not equal"
252 << failure_info_str;
253 }
254}
255
256TEST_F(PeerConnectionIceUnitTest, OfferContainsGatheredCandidates) {
257 const SocketAddress kLocalAddress("1.1.1.1", 0);
258
259 auto caller = CreatePeerConnectionWithAudioVideo();
260 caller->network()->AddInterface(kLocalAddress);
261
262 // Start ICE candidate gathering by setting the local offer.
263 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
264
265 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
266
267 auto offer = caller->CreateOffer();
268 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
269 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
270 offer->candidates(0)->count());
271 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
272 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
273 offer->candidates(1)->count());
274}
275
276TEST_F(PeerConnectionIceUnitTest, AnswerContainsGatheredCandidates) {
277 const SocketAddress kCallerAddress("1.1.1.1", 0);
278
279 auto caller = CreatePeerConnectionWithAudioVideo();
280 auto callee = CreatePeerConnectionWithAudioVideo();
281 caller->network()->AddInterface(kCallerAddress);
282
283 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
284 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
285
286 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
287
288 auto answer = callee->CreateAnswer();
289 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
290 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
291 answer->candidates(0)->count());
292 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
293 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
294 answer->candidates(1)->count());
295}
296
297TEST_F(PeerConnectionIceUnitTest,
298 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
299 const SocketAddress kCallerAddress("1.1.1.1", 1111);
300
301 auto caller = CreatePeerConnectionWithAudioVideo();
302 auto callee = CreatePeerConnectionWithAudioVideo();
303
304 auto offer = caller->CreateOfferAndSetAsLocal();
305 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
306 AddCandidateToFirstTransport(&candidate, offer.get());
307
308 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
309 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
310 ASSERT_EQ(1u, remote_candidates.size());
311 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
312 remote_candidates[0]->candidate());
313}
314
315TEST_F(PeerConnectionIceUnitTest, SetLocalDescriptionFailsIfNoIceCredentials) {
316 auto caller = CreatePeerConnectionWithAudioVideo();
317
318 auto offer = caller->CreateOffer();
319 RemoveIceUfragPwd(offer.get());
320
321 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
322}
323
324TEST_F(PeerConnectionIceUnitTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
325 auto caller = CreatePeerConnectionWithAudioVideo();
326 auto callee = CreatePeerConnectionWithAudioVideo();
327
328 auto offer = caller->CreateOfferAndSetAsLocal();
329 RemoveIceUfragPwd(offer.get());
330
331 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
332}
333
334// The following group tests that ICE candidates are not generated before
335// SetLocalDescription is called on a PeerConnection.
336
337TEST_F(PeerConnectionIceUnitTest, NoIceCandidatesBeforeSetLocalDescription) {
338 const SocketAddress kLocalAddress("1.1.1.1", 0);
339
340 auto caller = CreatePeerConnectionWithAudioVideo();
341 caller->network()->AddInterface(kLocalAddress);
342
343 // Pump for 1 second and verify that no candidates are generated.
344 rtc::Thread::Current()->ProcessMessages(1000);
345
346 EXPECT_EQ(0u, caller->observer()->candidates_.size());
347}
348TEST_F(PeerConnectionIceUnitTest,
349 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
350 const SocketAddress kCallerAddress("1.1.1.1", 1111);
351
352 auto caller = CreatePeerConnectionWithAudioVideo();
353 auto callee = CreatePeerConnectionWithAudioVideo();
354 caller->network()->AddInterface(kCallerAddress);
355
356 auto offer = caller->CreateOfferAndSetAsLocal();
357 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
358 AddCandidateToFirstTransport(&candidate, offer.get());
359 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
360
361 // Pump for 1 second and verify that no candidates are generated.
362 rtc::Thread::Current()->ProcessMessages(1000);
363
364 EXPECT_EQ(0u, callee->observer()->candidates_.size());
365}
366
367TEST_F(PeerConnectionIceUnitTest,
368 CannotAddCandidateWhenRemoteDescriptionNotSet) {
369 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
370
371 auto caller = CreatePeerConnectionWithAudioVideo();
372 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
373 JsepIceCandidate jsep_candidate(cricket::CN_AUDIO, 0, candidate);
374
375 EXPECT_FALSE(caller->pc()->AddIceCandidate(&jsep_candidate));
376
377 caller->CreateOfferAndSetAsLocal();
378
379 EXPECT_FALSE(caller->pc()->AddIceCandidate(&jsep_candidate));
380}
381
382TEST_F(PeerConnectionIceUnitTest, DuplicateIceCandidateIgnoredWhenAdded) {
383 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
384
385 auto caller = CreatePeerConnectionWithAudioVideo();
386 auto callee = CreatePeerConnectionWithAudioVideo();
387
388 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
389 ASSERT_TRUE(
390 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
391
392 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
393 caller->AddIceCandidate(&candidate);
394 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
395 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
396}
397
398TEST_F(PeerConnectionIceUnitTest,
399 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
400 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
401
402 auto caller = CreatePeerConnectionWithAudioVideo();
403 auto callee = CreatePeerConnectionWithAudioVideo();
404
405 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
406 ASSERT_TRUE(
407 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
408
409 // |candidate.transport_name()| is empty.
410 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
411 JsepIceCandidate ice_candidate(cricket::CN_AUDIO, 0, candidate);
412 EXPECT_TRUE(caller->pc()->AddIceCandidate(&ice_candidate));
413 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
414}
415
416TEST_F(PeerConnectionIceUnitTest, RemoveCandidateRemovesFromRemoteDescription) {
417 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
418
419 auto caller = CreatePeerConnectionWithAudioVideo();
420 auto callee = CreatePeerConnectionWithAudioVideo();
421
422 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
423 ASSERT_TRUE(
424 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
425
426 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
427 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
428 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
429 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
430}
431
432// Test that if a candidate is added via AddIceCandidate and via an updated
433// remote description, then both candidates appear in the stored remote
434// description.
435TEST_F(PeerConnectionIceUnitTest,
436 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
437 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
438 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
439
440 auto caller = CreatePeerConnectionWithAudioVideo();
441 auto callee = CreatePeerConnectionWithAudioVideo();
442
443 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
444 ASSERT_TRUE(
445 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
446
447 // Add one candidate via |AddIceCandidate|.
448 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
449 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
450
451 // Add the second candidate via a reoffer.
452 auto offer = caller->CreateOffer();
453 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
454 AddCandidateToFirstTransport(&candidate2, offer.get());
455
456 // Expect both candidates to appear in the callee's remote description.
457 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
458 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
459}
460
461// The follow test verifies that SetLocal/RemoteDescription fails when an offer
462// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
463// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
464// pwd must be 22-256 characters and ufrag must be 4-256 characters.
465TEST_F(PeerConnectionIceUnitTest, VerifyUfragPwdLength) {
466 auto caller = CreatePeerConnectionWithAudioVideo();
467 auto callee = CreatePeerConnectionWithAudioVideo();
468
469 auto set_local_description_with_ufrag_pwd_length =
470 [this, &caller](int ufrag_len, int pwd_len) {
471 auto offer = caller->CreateOffer();
472 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
473 std::string(pwd_len, 'x'));
474 return caller->SetLocalDescription(std::move(offer));
475 };
476
477 auto set_remote_description_with_ufrag_pwd_length =
478 [this, &caller, &callee](int ufrag_len, int pwd_len) {
479 auto offer = caller->CreateOffer();
480 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
481 std::string(pwd_len, 'x'));
482 return callee->SetRemoteDescription(std::move(offer));
483 };
484
485 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
486 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
487 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
488 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
489 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
490 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
491 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
492 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
493 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
494 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
495 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
496 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
497}
498
499::testing::AssertionResult AssertIpInCandidates(
500 const char* address_expr,
501 const char* candidates_expr,
502 const SocketAddress& address,
503 const std::vector<IceCandidateInterface*> candidates) {
504 std::stringstream candidate_hosts;
505 for (const auto* candidate : candidates) {
506 const auto& candidate_ip = candidate->candidate().address().ipaddr();
507 if (candidate_ip == address.ipaddr()) {
508 return ::testing::AssertionSuccess();
509 }
510 candidate_hosts << "\n" << candidate_ip;
511 }
512 return ::testing::AssertionFailure()
513 << address_expr << " (host " << address.HostAsURIString()
514 << ") not in " << candidates_expr
515 << " which have the following address hosts:" << candidate_hosts.str();
516}
517
518TEST_F(PeerConnectionIceUnitTest, CandidatesGeneratedForEachLocalInterface) {
519 const SocketAddress kLocalAddress1("1.1.1.1", 0);
520 const SocketAddress kLocalAddress2("2.2.2.2", 0);
521
522 auto caller = CreatePeerConnectionWithAudioVideo();
523 caller->network()->AddInterface(kLocalAddress1);
524 caller->network()->AddInterface(kLocalAddress2);
525
526 caller->CreateOfferAndSetAsLocal();
527 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
528
529 auto candidates = caller->observer()->GetCandidatesByMline(0);
530 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
531 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
532}
533
534TEST_F(PeerConnectionIceUnitTest,
535 TrickledSingleCandidateAddedToRemoteDescription) {
536 const SocketAddress kCallerAddress("1.1.1.1", 1111);
537
538 auto caller = CreatePeerConnectionWithAudioVideo();
539 auto callee = CreatePeerConnectionWithAudioVideo();
540
541 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
542
543 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
544 callee->AddIceCandidate(&candidate);
545 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
546 ASSERT_EQ(1u, candidates.size());
547 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
548 candidates[0]->candidate());
549}
550
551TEST_F(PeerConnectionIceUnitTest,
552 TwoTrickledCandidatesAddedToRemoteDescription) {
553 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
554 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
555
556 auto caller = CreatePeerConnectionWithAudioVideo();
557 auto callee = CreatePeerConnectionWithAudioVideo();
558
559 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
560 ASSERT_TRUE(
561 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
562
563 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
564 caller->AddIceCandidate(&candidate1);
565
566 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
567 caller->AddIceCandidate(&candidate2);
568
569 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
570 ASSERT_EQ(2u, candidates.size());
571 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
572 candidates[0]->candidate());
573 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
574 candidates[1]->candidate());
575}
576
577TEST_F(PeerConnectionIceUnitTest,
578 LocalDescriptionUpdatedWhenContinualGathering) {
579 const SocketAddress kLocalAddress("1.1.1.1", 0);
580
581 RTCConfiguration config;
582 config.continual_gathering_policy =
583 PeerConnectionInterface::GATHER_CONTINUALLY;
584 auto caller = CreatePeerConnectionWithAudioVideo(config);
585 caller->network()->AddInterface(kLocalAddress);
586
587 // Start ICE candidate gathering by setting the local offer.
588 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
589
590 // Since we're using continual gathering, we won't get "gathering done".
591 EXPECT_TRUE_WAIT(
592 caller->pc()->local_description()->candidates(0)->count() > 0,
593 kIceCandidatesTimeout);
594}
595
596// Test that when continual gathering is enabled, and a network interface goes
597// down, the candidate is signaled as removed and removed from the local
598// description.
599TEST_F(PeerConnectionIceUnitTest,
600 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
601 const SocketAddress kLocalAddress("1.1.1.1", 0);
602
603 RTCConfiguration config;
604 config.continual_gathering_policy =
605 PeerConnectionInterface::GATHER_CONTINUALLY;
606 auto caller = CreatePeerConnectionWithAudioVideo(config);
607 caller->network()->AddInterface(kLocalAddress);
608
609 // Start ICE candidate gathering by setting the local offer.
610 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
611
612 EXPECT_TRUE_WAIT(
613 caller->pc()->local_description()->candidates(0)->count() > 0,
614 kIceCandidatesTimeout);
615
616 // Remove the only network interface, causing the PeerConnection to signal
617 // the removal of all candidates derived from this interface.
618 caller->network()->RemoveInterface(kLocalAddress);
619
620 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
621 kIceCandidatesTimeout);
622 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
623}
624
625TEST_F(PeerConnectionIceUnitTest,
626 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
627 const SocketAddress kLocalAddress("1.1.1.1", 0);
628
629 RTCConfiguration config;
630 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
631 auto caller = CreatePeerConnectionWithAudioVideo(config);
632 caller->network()->AddInterface(kLocalAddress);
633
634 // Start ICE candidate gathering by setting the local offer.
635 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
636
637 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
638
639 caller->network()->RemoveInterface(kLocalAddress);
640
641 // Verify that the local candidates are not removed;
642 rtc::Thread::Current()->ProcessMessages(1000);
643 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
644}
645
646// The following group tests that when an offer includes a new ufrag or pwd
647// (indicating an ICE restart) the old candidates are removed and new candidates
648// added to the remote description.
649
650TEST_F(PeerConnectionIceUnitTest, IceRestartOfferClearsExistingCandidate) {
651 const SocketAddress kCallerAddress("1.1.1.1", 1111);
652
653 auto caller = CreatePeerConnectionWithAudioVideo();
654 auto callee = CreatePeerConnectionWithAudioVideo();
655
656 auto offer = caller->CreateOffer();
657 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
658 AddCandidateToFirstTransport(&candidate, offer.get());
659
660 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
661
662 RTCOfferAnswerOptions options;
663 options.ice_restart = true;
664 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer(options)));
665
666 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
667}
668TEST_F(PeerConnectionIceUnitTest,
669 IceRestartOfferCandidateReplacesExistingCandidate) {
670 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
671 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
672
673 auto caller = CreatePeerConnectionWithAudioVideo();
674 auto callee = CreatePeerConnectionWithAudioVideo();
675
676 auto offer = caller->CreateOffer();
677 cricket::Candidate old_candidate =
678 CreateLocalUdpCandidate(kFirstCallerAddress);
679 AddCandidateToFirstTransport(&old_candidate, offer.get());
680
681 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
682
683 RTCOfferAnswerOptions options;
684 options.ice_restart = true;
685 auto restart_offer = caller->CreateOffer(options);
686 cricket::Candidate new_candidate =
687 CreateLocalUdpCandidate(kRestartedCallerAddress);
688 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
689
690 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
691
692 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
693 ASSERT_EQ(1u, remote_candidates.size());
694 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
695 remote_candidates[0]->candidate());
696}
697
698// Test that if there is not an ICE restart (i.e., nothing changes), then the
699// answer to a later offer should have the same ufrag/pwd as the first answer.
700TEST_F(PeerConnectionIceUnitTest,
701 LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
702 auto caller = CreatePeerConnectionWithAudioVideo();
703 auto callee = CreatePeerConnectionWithAudioVideo();
704
705 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
706 ASSERT_TRUE(
707 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
708
709 // Re-offer.
710 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
711
712 auto answer = callee->CreateAnswer();
713 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
714 auto* local_transport_desc =
715 GetFirstTransportDescription(callee->pc()->local_description());
716
717 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
718 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
719}
720
721// The following parameterized test verifies that if an offer is sent with a
722// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
723// other side has initiated an ICE restart and generate a new ufrag and pwd.
724// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
725// a=ice-pwd attributes compared to the previous SDP from the peer, it
726// indicates that ICE is restarting for this media stream."
727
728class PeerConnectionIceUfragPwdAnswerUnitTest
729 : public PeerConnectionIceUnitTest,
730 public ::testing::WithParamInterface<std::pair<bool, bool>> {
731 protected:
732 PeerConnectionIceUfragPwdAnswerUnitTest() {
733 offer_new_ufrag_ = GetParam().first;
734 offer_new_pwd_ = GetParam().second;
735 }
736
737 bool offer_new_ufrag_;
738 bool offer_new_pwd_;
739};
740
741TEST_P(PeerConnectionIceUfragPwdAnswerUnitTest, TestIncludedInAnswer) {
742 auto caller = CreatePeerConnectionWithAudioVideo();
743 auto callee = CreatePeerConnectionWithAudioVideo();
744
745 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
746 ASSERT_TRUE(
747 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
748
749 auto offer = caller->CreateOffer();
750 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
751 if (offer_new_ufrag_) {
752 offer_transport_desc->ice_ufrag += "_new";
753 }
754 if (offer_new_pwd_) {
755 offer_transport_desc->ice_pwd += "_new";
756 }
757
758 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
759
760 auto answer = callee->CreateAnswer();
761 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
762 auto* local_transport_desc =
763 GetFirstTransportDescription(callee->pc()->local_description());
764
765 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
766 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
767}
768
769INSTANTIATE_TEST_CASE_P(
770 PeerConnectionIceUnitTest,
771 PeerConnectionIceUfragPwdAnswerUnitTest,
772 Values(std::make_pair(true, true), // Both changed.
773 std::make_pair(true, false), // Only ufrag changed.
774 std::make_pair(false, true))); // Only pwd changed.
775
776// Test that if an ICE restart is offered on one media section, then the answer
777// will only change ICE ufrag/pwd for that section and keep the other sections
778// the same.
779// Note that this only works if we have disabled BUNDLE, otherwise all media
780// sections will share the same transport.
781TEST_F(PeerConnectionIceUnitTest,
782 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
783 auto caller = CreatePeerConnectionWithAudioVideo();
784 auto callee = CreatePeerConnectionWithAudioVideo();
785
786 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
787 ASSERT_TRUE(
788 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
789
790 RTCOfferAnswerOptions disable_bundle_options;
791 disable_bundle_options.use_rtp_mux = false;
792
793 auto offer = caller->CreateOffer(disable_bundle_options);
794
795 // Signal ICE restart on the first media section.
796 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
797 offer_transport_desc->ice_ufrag += "_new";
798 offer_transport_desc->ice_pwd += "_new";
799
800 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
801
802 auto answer = callee->CreateAnswer(disable_bundle_options);
803 const auto& answer_transports = answer->description()->transport_infos();
804 const auto& local_transports =
805 callee->pc()->local_description()->description()->transport_infos();
806
807 EXPECT_NE(answer_transports[0].description.ice_ufrag,
808 local_transports[0].description.ice_ufrag);
809 EXPECT_NE(answer_transports[0].description.ice_pwd,
810 local_transports[0].description.ice_pwd);
811 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
812 local_transports[1].description.ice_ufrag);
813 EXPECT_EQ(answer_transports[1].description.ice_pwd,
814 local_transports[1].description.ice_pwd);
815}
816
Qingsi Wange1692722017-11-29 13:27:20 -0800817// Test that when the initial offerer (caller) uses the lite implementation of
818// ICE and the callee uses the full implementation, the caller takes the
819// CONTROLLED role and the callee takes the CONTROLLING role. This is specified
820// in RFC5245 Section 5.1.1.
821TEST_F(PeerConnectionIceUnitTest,
822 OfferFromLiteIceControlledAndAnswerFromFullIceControlling) {
823 auto caller = CreatePeerConnectionWithAudioVideo();
824 auto callee = CreatePeerConnectionWithAudioVideo();
825
826 auto offer = caller->CreateOffer();
827 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
828 ASSERT_TRUE(
829 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
830 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
831
832 auto answer = callee->CreateAnswer();
833 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_FULL);
834 ASSERT_TRUE(
835 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
836 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
837
838 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(caller));
839 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(callee));
840}
841
842// Test that when the caller and the callee both use the lite implementation of
843// ICE, the initial offerer (caller) takes the CONTROLLING role and the callee
844// takes the CONTROLLED role. This is specified in RFC5245 Section 5.1.1.
845TEST_F(PeerConnectionIceUnitTest,
846 OfferFromLiteIceControllingAndAnswerFromLiteIceControlled) {
847 auto caller = CreatePeerConnectionWithAudioVideo();
848 auto callee = CreatePeerConnectionWithAudioVideo();
849
850 auto offer = caller->CreateOffer();
851 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
852 ASSERT_TRUE(
853 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
854 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
855
856 auto answer = callee->CreateAnswer();
857 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_LITE);
858 ASSERT_TRUE(
859 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
860 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
861
862 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(caller));
863 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(callee));
864}
865
Steve Antonf1c6db12017-10-13 11:13:35 -0700866} // namespace webrtc