blob: 965956c42a3241b1180e5db8735814ede36f5375 [file] [log] [blame]
Steve Antonf1c6db12017-10-13 11:13:35 -07001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "p2p/base/fakeportallocator.h"
12#include "p2p/base/teststunserver.h"
13#include "p2p/client/basicportallocator.h"
14#include "pc/mediasession.h"
Qingsi Wange1692722017-11-29 13:27:20 -080015#include "pc/peerconnection.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070016#include "pc/peerconnectionwrapper.h"
17#include "pc/sdputils.h"
18#ifdef WEBRTC_ANDROID
19#include "pc/test/androidtestinitializer.h"
20#endif
Karl Wiberg918f50c2018-07-05 11:40:33 +020021#include "absl/memory/memory.h"
Karl Wiberg1b0eae32017-10-17 14:48:54 +020022#include "api/audio_codecs/builtin_audio_decoder_factory.h"
23#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Qingsi Wange1692722017-11-29 13:27:20 -080024#include "api/peerconnectionproxy.h"
Anders Carlsson67537952018-05-03 11:28:29 +020025#include "api/video_codecs/builtin_video_decoder_factory.h"
26#include "api/video_codecs/builtin_video_encoder_factory.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070027#include "pc/test/fakeaudiocapturemodule.h"
28#include "rtc_base/fakenetwork.h"
29#include "rtc_base/gunit.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020030#include "rtc_base/strings/string_builder.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070031#include "rtc_base/virtualsocketserver.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020032#include "system_wrappers/include/metrics.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070033
34namespace webrtc {
35
36using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
37using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
38using rtc::SocketAddress;
Steve Anton46d926a2018-01-23 10:23:06 -080039using ::testing::Combine;
Steve Antonf1c6db12017-10-13 11:13:35 -070040using ::testing::Values;
41
42constexpr int kIceCandidatesTimeout = 10000;
43
Steve Anton46d926a2018-01-23 10:23:06 -080044class PeerConnectionWrapperForIceTest : public PeerConnectionWrapper {
Steve Antonf1c6db12017-10-13 11:13:35 -070045 public:
46 using PeerConnectionWrapper::PeerConnectionWrapper;
47
48 // Adds a new ICE candidate to the first transport.
49 bool AddIceCandidate(cricket::Candidate* candidate) {
50 RTC_DCHECK(pc()->remote_description());
51 const auto* desc = pc()->remote_description()->description();
52 RTC_DCHECK(desc->contents().size() > 0);
53 const auto& first_content = desc->contents()[0];
54 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -070055 std::unique_ptr<IceCandidateInterface> jsep_candidate =
56 CreateIceCandidate(first_content.name, 0, *candidate);
57 return pc()->AddIceCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -070058 }
59
60 // Returns ICE candidates from the remote session description.
61 std::vector<const IceCandidateInterface*>
62 GetIceCandidatesFromRemoteDescription() {
63 const SessionDescriptionInterface* sdesc = pc()->remote_description();
64 RTC_DCHECK(sdesc);
65 std::vector<const IceCandidateInterface*> candidates;
66 for (size_t mline_index = 0; mline_index < sdesc->number_of_mediasections();
67 mline_index++) {
68 const auto* candidate_collection = sdesc->candidates(mline_index);
69 for (size_t i = 0; i < candidate_collection->count(); i++) {
70 candidates.push_back(candidate_collection->at(i));
71 }
72 }
73 return candidates;
74 }
75
76 rtc::FakeNetworkManager* network() { return network_; }
77
78 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
79
80 private:
81 rtc::FakeNetworkManager* network_;
82};
83
Steve Anton46d926a2018-01-23 10:23:06 -080084class PeerConnectionIceBaseTest : public ::testing::Test {
Steve Antonf1c6db12017-10-13 11:13:35 -070085 protected:
Steve Anton46d926a2018-01-23 10:23:06 -080086 typedef std::unique_ptr<PeerConnectionWrapperForIceTest> WrapperPtr;
Steve Antonf1c6db12017-10-13 11:13:35 -070087
Steve Anton46d926a2018-01-23 10:23:06 -080088 explicit PeerConnectionIceBaseTest(SdpSemantics sdp_semantics)
89 : vss_(new rtc::VirtualSocketServer()),
90 main_(vss_.get()),
91 sdp_semantics_(sdp_semantics) {
Steve Antonf1c6db12017-10-13 11:13:35 -070092#ifdef WEBRTC_ANDROID
93 InitializeAndroidObjects();
94#endif
95 pc_factory_ = CreatePeerConnectionFactory(
96 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Anders Carlsson67537952018-05-03 11:28:29 +020097 rtc::scoped_refptr<AudioDeviceModule>(FakeAudioCaptureModule::Create()),
98 CreateBuiltinAudioEncoderFactory(), CreateBuiltinAudioDecoderFactory(),
99 CreateBuiltinVideoEncoderFactory(), CreateBuiltinVideoDecoderFactory(),
100 nullptr /* audio_mixer */, nullptr /* audio_processing */);
Steve Antonf1c6db12017-10-13 11:13:35 -0700101 }
102
103 WrapperPtr CreatePeerConnection() {
104 return CreatePeerConnection(RTCConfiguration());
105 }
106
107 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
108 auto* fake_network = NewFakeNetwork();
109 auto port_allocator =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200110 absl::make_unique<cricket::BasicPortAllocator>(fake_network);
Steve Antonf1c6db12017-10-13 11:13:35 -0700111 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
112 cricket::PORTALLOCATOR_DISABLE_RELAY);
113 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
Steve Anton46d926a2018-01-23 10:23:06 -0800114 RTCConfiguration modified_config = config;
115 modified_config.sdp_semantics = sdp_semantics_;
Karl Wiberg918f50c2018-07-05 11:40:33 +0200116 auto observer = absl::make_unique<MockPeerConnectionObserver>();
Steve Antonf1c6db12017-10-13 11:13:35 -0700117 auto pc = pc_factory_->CreatePeerConnection(
Steve Anton46d926a2018-01-23 10:23:06 -0800118 modified_config, std::move(port_allocator), nullptr, observer.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700119 if (!pc) {
120 return nullptr;
121 }
122
Karl Wiberg918f50c2018-07-05 11:40:33 +0200123 auto wrapper = absl::make_unique<PeerConnectionWrapperForIceTest>(
Steve Antonf1c6db12017-10-13 11:13:35 -0700124 pc_factory_, pc, std::move(observer));
125 wrapper->set_network(fake_network);
126 return wrapper;
127 }
128
129 // Accepts the same arguments as CreatePeerConnection and adds default audio
130 // and video tracks.
131 template <typename... Args>
132 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
133 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
134 if (!wrapper) {
135 return nullptr;
136 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700137 wrapper->AddAudioTrack("a");
138 wrapper->AddVideoTrack("v");
Steve Antonf1c6db12017-10-13 11:13:35 -0700139 return wrapper;
140 }
141
142 cricket::Candidate CreateLocalUdpCandidate(
143 const rtc::SocketAddress& address) {
144 cricket::Candidate candidate;
145 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
146 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
147 candidate.set_address(address);
148 candidate.set_type(cricket::LOCAL_PORT_TYPE);
149 return candidate;
150 }
151
152 // Remove all ICE ufrag/pwd lines from the given session description.
153 void RemoveIceUfragPwd(SessionDescriptionInterface* sdesc) {
154 SetIceUfragPwd(sdesc, "", "");
155 }
156
157 // Sets all ICE ufrag/pwds on the given session description.
158 void SetIceUfragPwd(SessionDescriptionInterface* sdesc,
159 const std::string& ufrag,
160 const std::string& pwd) {
161 auto* desc = sdesc->description();
162 for (const auto& content : desc->contents()) {
163 auto* transport_info = desc->GetTransportInfoByName(content.name);
164 transport_info->description.ice_ufrag = ufrag;
165 transport_info->description.ice_pwd = pwd;
166 }
167 }
168
Qingsi Wange1692722017-11-29 13:27:20 -0800169 // Set ICE mode on the given session description.
170 void SetIceMode(SessionDescriptionInterface* sdesc,
171 const cricket::IceMode ice_mode) {
172 auto* desc = sdesc->description();
173 for (const auto& content : desc->contents()) {
174 auto* transport_info = desc->GetTransportInfoByName(content.name);
175 transport_info->description.ice_mode = ice_mode;
176 }
177 }
178
Steve Antonf1c6db12017-10-13 11:13:35 -0700179 cricket::TransportDescription* GetFirstTransportDescription(
180 SessionDescriptionInterface* sdesc) {
181 auto* desc = sdesc->description();
182 RTC_DCHECK(desc->contents().size() > 0);
183 auto* transport_info =
184 desc->GetTransportInfoByName(desc->contents()[0].name);
185 RTC_DCHECK(transport_info);
186 return &transport_info->description;
187 }
188
189 const cricket::TransportDescription* GetFirstTransportDescription(
190 const SessionDescriptionInterface* sdesc) {
191 auto* desc = sdesc->description();
192 RTC_DCHECK(desc->contents().size() > 0);
193 auto* transport_info =
194 desc->GetTransportInfoByName(desc->contents()[0].name);
195 RTC_DCHECK(transport_info);
196 return &transport_info->description;
197 }
198
Qingsi Wange1692722017-11-29 13:27:20 -0800199 // TODO(qingsi): Rewrite this method in terms of the standard IceTransport
200 // after it is implemented.
201 cricket::IceRole GetIceRole(const WrapperPtr& pc_wrapper_ptr) {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100202 auto* pc_proxy =
203 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
204 pc_wrapper_ptr->pc());
205 PeerConnection* pc = static_cast<PeerConnection*>(pc_proxy->internal());
Steve Antonb8867112018-02-13 10:07:54 -0800206 for (auto transceiver : pc->GetTransceiversInternal()) {
Steve Anton69470252018-02-09 11:43:08 -0800207 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Steve Anton46d926a2018-01-23 10:23:06 -0800208 cricket::BaseChannel* channel = transceiver->internal()->channel();
209 if (channel) {
Zhi Huange830e682018-03-30 10:48:35 -0700210 auto dtls_transport = static_cast<cricket::DtlsTransportInternal*>(
211 channel->rtp_packet_transport());
212 return dtls_transport->ice_transport()->GetIceRole();
Steve Anton46d926a2018-01-23 10:23:06 -0800213 }
214 }
215 }
216 RTC_NOTREACHED();
217 return cricket::ICEROLE_UNKNOWN;
Qingsi Wange1692722017-11-29 13:27:20 -0800218 }
219
Steve Antonf1c6db12017-10-13 11:13:35 -0700220 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
221 SessionDescriptionInterface* sdesc) {
222 auto* desc = sdesc->description();
223 RTC_DCHECK(desc->contents().size() > 0);
224 const auto& first_content = desc->contents()[0];
225 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -0700226 std::unique_ptr<IceCandidateInterface> jsep_candidate =
227 CreateIceCandidate(first_content.name, 0, *candidate);
228 return sdesc->AddCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700229 }
230
231 rtc::FakeNetworkManager* NewFakeNetwork() {
232 // The PeerConnection's port allocator is tied to the PeerConnection's
233 // lifetime and expects the underlying NetworkManager to outlive it. That
234 // prevents us from having the PeerConnectionWrapper own the fake network.
235 // Therefore, the test fixture will own all the fake networks even though
236 // tests should access the fake network through the PeerConnectionWrapper.
237 auto* fake_network = new rtc::FakeNetworkManager();
238 fake_networks_.emplace_back(fake_network);
239 return fake_network;
240 }
241
242 std::unique_ptr<rtc::VirtualSocketServer> vss_;
243 rtc::AutoSocketServerThread main_;
244 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
245 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton46d926a2018-01-23 10:23:06 -0800246 const SdpSemantics sdp_semantics_;
247};
248
249class PeerConnectionIceTest
250 : public PeerConnectionIceBaseTest,
251 public ::testing::WithParamInterface<SdpSemantics> {
252 protected:
Harald Alvestrand76829d72018-07-18 23:24:36 +0200253 PeerConnectionIceTest() : PeerConnectionIceBaseTest(GetParam()) {
254 webrtc::metrics::Reset();
255 }
Steve Antonf1c6db12017-10-13 11:13:35 -0700256};
257
258::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
259 const char* b_expr,
260 const cricket::Candidate& a,
261 const cricket::Candidate& b) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200262 rtc::StringBuilder failure_info;
Steve Antonf1c6db12017-10-13 11:13:35 -0700263 if (a.component() != b.component()) {
264 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
265 }
266 if (a.protocol() != b.protocol()) {
267 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
268 }
269 if (a.address() != b.address()) {
270 failure_info << "\naddress: " << a.address().ToString()
271 << " != " << b.address().ToString();
272 }
273 if (a.type() != b.type()) {
274 failure_info << "\ntype: " << a.type() << " != " << b.type();
275 }
276 std::string failure_info_str = failure_info.str();
277 if (failure_info_str.empty()) {
278 return ::testing::AssertionSuccess();
279 } else {
280 return ::testing::AssertionFailure()
281 << a_expr << " and " << b_expr << " are not equal"
282 << failure_info_str;
283 }
284}
285
Steve Anton46d926a2018-01-23 10:23:06 -0800286TEST_P(PeerConnectionIceTest, OfferContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700287 const SocketAddress kLocalAddress("1.1.1.1", 0);
288
289 auto caller = CreatePeerConnectionWithAudioVideo();
290 caller->network()->AddInterface(kLocalAddress);
291
292 // Start ICE candidate gathering by setting the local offer.
293 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
294
295 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
296
297 auto offer = caller->CreateOffer();
298 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
299 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
300 offer->candidates(0)->count());
301 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
302 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
303 offer->candidates(1)->count());
304}
305
Steve Anton46d926a2018-01-23 10:23:06 -0800306TEST_P(PeerConnectionIceTest, AnswerContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700307 const SocketAddress kCallerAddress("1.1.1.1", 0);
308
309 auto caller = CreatePeerConnectionWithAudioVideo();
310 auto callee = CreatePeerConnectionWithAudioVideo();
311 caller->network()->AddInterface(kCallerAddress);
312
313 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
314 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
315
316 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
317
Steve Antondffead82018-02-06 10:31:29 -0800318 auto* answer = callee->pc()->local_description();
Steve Antonf1c6db12017-10-13 11:13:35 -0700319 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
320 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
321 answer->candidates(0)->count());
322 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
323 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
324 answer->candidates(1)->count());
325}
326
Steve Anton46d926a2018-01-23 10:23:06 -0800327TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700328 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
329 const SocketAddress kCallerAddress("1.1.1.1", 1111);
330
331 auto caller = CreatePeerConnectionWithAudioVideo();
332 auto callee = CreatePeerConnectionWithAudioVideo();
333
334 auto offer = caller->CreateOfferAndSetAsLocal();
335 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
336 AddCandidateToFirstTransport(&candidate, offer.get());
337
338 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
339 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
340 ASSERT_EQ(1u, remote_candidates.size());
341 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
342 remote_candidates[0]->candidate());
343}
344
Steve Anton46d926a2018-01-23 10:23:06 -0800345TEST_P(PeerConnectionIceTest, SetLocalDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700346 auto caller = CreatePeerConnectionWithAudioVideo();
347
348 auto offer = caller->CreateOffer();
349 RemoveIceUfragPwd(offer.get());
350
351 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
352}
353
Steve Anton46d926a2018-01-23 10:23:06 -0800354TEST_P(PeerConnectionIceTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700355 auto caller = CreatePeerConnectionWithAudioVideo();
356 auto callee = CreatePeerConnectionWithAudioVideo();
357
358 auto offer = caller->CreateOfferAndSetAsLocal();
359 RemoveIceUfragPwd(offer.get());
360
361 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
362}
363
Steve Antonf764cf42018-05-01 14:32:17 -0700364// Test that doing an offer/answer exchange with no transport (i.e., no data
365// channel or media) results in the ICE connection state staying at New.
366TEST_P(PeerConnectionIceTest,
367 OfferAnswerWithNoTransportsDoesNotChangeIceConnectionState) {
368 auto caller = CreatePeerConnection();
369 auto callee = CreatePeerConnection();
370
371 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
372
373 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
374 caller->pc()->ice_connection_state());
375 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
376 callee->pc()->ice_connection_state());
377}
378
Steve Antonf1c6db12017-10-13 11:13:35 -0700379// The following group tests that ICE candidates are not generated before
380// SetLocalDescription is called on a PeerConnection.
381
Steve Anton46d926a2018-01-23 10:23:06 -0800382TEST_P(PeerConnectionIceTest, NoIceCandidatesBeforeSetLocalDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700383 const SocketAddress kLocalAddress("1.1.1.1", 0);
384
385 auto caller = CreatePeerConnectionWithAudioVideo();
386 caller->network()->AddInterface(kLocalAddress);
387
388 // Pump for 1 second and verify that no candidates are generated.
389 rtc::Thread::Current()->ProcessMessages(1000);
390
391 EXPECT_EQ(0u, caller->observer()->candidates_.size());
392}
Steve Anton46d926a2018-01-23 10:23:06 -0800393TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700394 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
395 const SocketAddress kCallerAddress("1.1.1.1", 1111);
396
397 auto caller = CreatePeerConnectionWithAudioVideo();
398 auto callee = CreatePeerConnectionWithAudioVideo();
399 caller->network()->AddInterface(kCallerAddress);
400
401 auto offer = caller->CreateOfferAndSetAsLocal();
402 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
403 AddCandidateToFirstTransport(&candidate, offer.get());
404 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
405
406 // Pump for 1 second and verify that no candidates are generated.
407 rtc::Thread::Current()->ProcessMessages(1000);
408
409 EXPECT_EQ(0u, callee->observer()->candidates_.size());
410}
411
Steve Anton46d926a2018-01-23 10:23:06 -0800412TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenRemoteDescriptionNotSet) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700413 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
414
415 auto caller = CreatePeerConnectionWithAudioVideo();
416 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton27ab0e52018-07-23 15:11:53 -0700417 std::unique_ptr<IceCandidateInterface> jsep_candidate =
418 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
Steve Antonf1c6db12017-10-13 11:13:35 -0700419
Steve Anton27ab0e52018-07-23 15:11:53 -0700420 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700421
422 caller->CreateOfferAndSetAsLocal();
423
Steve Anton27ab0e52018-07-23 15:11:53 -0700424 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Harald Alvestrand76829d72018-07-18 23:24:36 +0200425 EXPECT_EQ(
426 2, webrtc::metrics::NumSamples("WebRTC.PeerConnection.AddIceCandidate"));
427 EXPECT_EQ(
428 2, webrtc::metrics::NumEvents("WebRTC.PeerConnection.AddIceCandidate",
429 kAddIceCandidateFailNoRemoteDescription));
Steve Antonf1c6db12017-10-13 11:13:35 -0700430}
431
Steve Antonc79268f2018-04-24 09:54:10 -0700432TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenPeerConnectionClosed) {
433 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
434
435 auto caller = CreatePeerConnectionWithAudioVideo();
436 auto callee = CreatePeerConnectionWithAudioVideo();
437
438 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
439
440 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
441 auto* audio_content = cricket::GetFirstAudioContent(
442 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700443 std::unique_ptr<IceCandidateInterface> jsep_candidate =
444 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700445
446 caller->pc()->Close();
447
Steve Anton27ab0e52018-07-23 15:11:53 -0700448 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700449}
450
Steve Anton46d926a2018-01-23 10:23:06 -0800451TEST_P(PeerConnectionIceTest, DuplicateIceCandidateIgnoredWhenAdded) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700452 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
453
454 auto caller = CreatePeerConnectionWithAudioVideo();
455 auto callee = CreatePeerConnectionWithAudioVideo();
456
457 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
458 ASSERT_TRUE(
459 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
460
461 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
462 caller->AddIceCandidate(&candidate);
463 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
464 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
465}
466
Steve Anton46d926a2018-01-23 10:23:06 -0800467TEST_P(PeerConnectionIceTest,
Steve Antonc79268f2018-04-24 09:54:10 -0700468 CannotRemoveIceCandidatesWhenPeerConnectionClosed) {
469 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
470
471 auto caller = CreatePeerConnectionWithAudioVideo();
472 auto callee = CreatePeerConnectionWithAudioVideo();
473
474 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
475
476 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
477 auto* audio_content = cricket::GetFirstAudioContent(
478 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700479 std::unique_ptr<IceCandidateInterface> ice_candidate =
480 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700481
Steve Anton27ab0e52018-07-23 15:11:53 -0700482 ASSERT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700483
484 caller->pc()->Close();
485
486 EXPECT_FALSE(caller->pc()->RemoveIceCandidates({candidate}));
487}
488
489TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700490 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
491 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
492
493 auto caller = CreatePeerConnectionWithAudioVideo();
494 auto callee = CreatePeerConnectionWithAudioVideo();
495
496 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
497 ASSERT_TRUE(
498 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
499
500 // |candidate.transport_name()| is empty.
501 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton46d926a2018-01-23 10:23:06 -0800502 auto* audio_content = cricket::GetFirstAudioContent(
503 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700504 std::unique_ptr<IceCandidateInterface> ice_candidate =
505 CreateIceCandidate(audio_content->name, 0, candidate);
506 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700507 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
508}
509
Steve Anton46d926a2018-01-23 10:23:06 -0800510TEST_P(PeerConnectionIceTest, RemoveCandidateRemovesFromRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700511 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
512
513 auto caller = CreatePeerConnectionWithAudioVideo();
514 auto callee = CreatePeerConnectionWithAudioVideo();
515
516 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
517 ASSERT_TRUE(
518 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
519
520 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
521 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
522 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
523 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
524}
525
526// Test that if a candidate is added via AddIceCandidate and via an updated
527// remote description, then both candidates appear in the stored remote
528// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800529TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700530 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
531 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
532 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
533
534 auto caller = CreatePeerConnectionWithAudioVideo();
535 auto callee = CreatePeerConnectionWithAudioVideo();
536
537 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
538 ASSERT_TRUE(
539 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
540
541 // Add one candidate via |AddIceCandidate|.
542 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
543 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
544
545 // Add the second candidate via a reoffer.
546 auto offer = caller->CreateOffer();
547 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
548 AddCandidateToFirstTransport(&candidate2, offer.get());
549
550 // Expect both candidates to appear in the callee's remote description.
551 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
552 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
553}
554
555// The follow test verifies that SetLocal/RemoteDescription fails when an offer
556// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
557// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
558// pwd must be 22-256 characters and ufrag must be 4-256 characters.
Steve Anton46d926a2018-01-23 10:23:06 -0800559TEST_P(PeerConnectionIceTest, VerifyUfragPwdLength) {
Yves Gerey665174f2018-06-19 15:03:05 +0200560 auto set_local_description_with_ufrag_pwd_length = [this](int ufrag_len,
561 int pwd_len) {
562 auto pc = CreatePeerConnectionWithAudioVideo();
563 auto offer = pc->CreateOffer();
564 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
565 std::string(pwd_len, 'x'));
566 return pc->SetLocalDescription(std::move(offer));
567 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700568
Yves Gerey665174f2018-06-19 15:03:05 +0200569 auto set_remote_description_with_ufrag_pwd_length = [this](int ufrag_len,
570 int pwd_len) {
571 auto pc = CreatePeerConnectionWithAudioVideo();
572 auto offer = pc->CreateOffer();
573 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
574 std::string(pwd_len, 'x'));
575 return pc->SetRemoteDescription(std::move(offer));
576 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700577
578 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
579 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
580 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
581 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
582 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
583 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
584 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
585 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
586 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
587 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
588 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
589 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
590}
591
592::testing::AssertionResult AssertIpInCandidates(
593 const char* address_expr,
594 const char* candidates_expr,
595 const SocketAddress& address,
596 const std::vector<IceCandidateInterface*> candidates) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200597 rtc::StringBuilder candidate_hosts;
Steve Antonf1c6db12017-10-13 11:13:35 -0700598 for (const auto* candidate : candidates) {
599 const auto& candidate_ip = candidate->candidate().address().ipaddr();
600 if (candidate_ip == address.ipaddr()) {
601 return ::testing::AssertionSuccess();
602 }
Jonas Olssonabbe8412018-04-03 13:40:05 +0200603 candidate_hosts << "\n" << candidate_ip.ToString();
Steve Antonf1c6db12017-10-13 11:13:35 -0700604 }
605 return ::testing::AssertionFailure()
606 << address_expr << " (host " << address.HostAsURIString()
607 << ") not in " << candidates_expr
608 << " which have the following address hosts:" << candidate_hosts.str();
609}
610
Steve Anton46d926a2018-01-23 10:23:06 -0800611TEST_P(PeerConnectionIceTest, CandidatesGeneratedForEachLocalInterface) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700612 const SocketAddress kLocalAddress1("1.1.1.1", 0);
613 const SocketAddress kLocalAddress2("2.2.2.2", 0);
614
615 auto caller = CreatePeerConnectionWithAudioVideo();
616 caller->network()->AddInterface(kLocalAddress1);
617 caller->network()->AddInterface(kLocalAddress2);
618
619 caller->CreateOfferAndSetAsLocal();
620 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
621
622 auto candidates = caller->observer()->GetCandidatesByMline(0);
623 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
624 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
625}
626
Steve Anton46d926a2018-01-23 10:23:06 -0800627TEST_P(PeerConnectionIceTest, TrickledSingleCandidateAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700628 const SocketAddress kCallerAddress("1.1.1.1", 1111);
629
630 auto caller = CreatePeerConnectionWithAudioVideo();
631 auto callee = CreatePeerConnectionWithAudioVideo();
632
633 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
634
635 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
636 callee->AddIceCandidate(&candidate);
637 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
638 ASSERT_EQ(1u, candidates.size());
639 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
640 candidates[0]->candidate());
641}
642
Steve Anton46d926a2018-01-23 10:23:06 -0800643TEST_P(PeerConnectionIceTest, TwoTrickledCandidatesAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700644 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
645 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
646
647 auto caller = CreatePeerConnectionWithAudioVideo();
648 auto callee = CreatePeerConnectionWithAudioVideo();
649
650 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
651 ASSERT_TRUE(
652 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
653
654 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
655 caller->AddIceCandidate(&candidate1);
656
657 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
658 caller->AddIceCandidate(&candidate2);
659
660 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
661 ASSERT_EQ(2u, candidates.size());
662 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
663 candidates[0]->candidate());
664 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
665 candidates[1]->candidate());
666}
667
Steve Anton46d926a2018-01-23 10:23:06 -0800668TEST_P(PeerConnectionIceTest, LocalDescriptionUpdatedWhenContinualGathering) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700669 const SocketAddress kLocalAddress("1.1.1.1", 0);
670
671 RTCConfiguration config;
672 config.continual_gathering_policy =
673 PeerConnectionInterface::GATHER_CONTINUALLY;
674 auto caller = CreatePeerConnectionWithAudioVideo(config);
675 caller->network()->AddInterface(kLocalAddress);
676
677 // Start ICE candidate gathering by setting the local offer.
678 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
679
680 // Since we're using continual gathering, we won't get "gathering done".
681 EXPECT_TRUE_WAIT(
682 caller->pc()->local_description()->candidates(0)->count() > 0,
683 kIceCandidatesTimeout);
684}
685
686// Test that when continual gathering is enabled, and a network interface goes
687// down, the candidate is signaled as removed and removed from the local
688// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800689TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700690 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
691 const SocketAddress kLocalAddress("1.1.1.1", 0);
692
693 RTCConfiguration config;
694 config.continual_gathering_policy =
695 PeerConnectionInterface::GATHER_CONTINUALLY;
696 auto caller = CreatePeerConnectionWithAudioVideo(config);
697 caller->network()->AddInterface(kLocalAddress);
698
699 // Start ICE candidate gathering by setting the local offer.
700 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
701
702 EXPECT_TRUE_WAIT(
703 caller->pc()->local_description()->candidates(0)->count() > 0,
704 kIceCandidatesTimeout);
705
706 // Remove the only network interface, causing the PeerConnection to signal
707 // the removal of all candidates derived from this interface.
708 caller->network()->RemoveInterface(kLocalAddress);
709
710 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
711 kIceCandidatesTimeout);
712 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
713}
714
Steve Anton46d926a2018-01-23 10:23:06 -0800715TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700716 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
717 const SocketAddress kLocalAddress("1.1.1.1", 0);
718
719 RTCConfiguration config;
720 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
721 auto caller = CreatePeerConnectionWithAudioVideo(config);
722 caller->network()->AddInterface(kLocalAddress);
723
724 // Start ICE candidate gathering by setting the local offer.
725 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
726
727 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
728
729 caller->network()->RemoveInterface(kLocalAddress);
730
731 // Verify that the local candidates are not removed;
732 rtc::Thread::Current()->ProcessMessages(1000);
733 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
734}
735
736// The following group tests that when an offer includes a new ufrag or pwd
737// (indicating an ICE restart) the old candidates are removed and new candidates
738// added to the remote description.
739
Steve Anton46d926a2018-01-23 10:23:06 -0800740TEST_P(PeerConnectionIceTest, IceRestartOfferClearsExistingCandidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700741 const SocketAddress kCallerAddress("1.1.1.1", 1111);
742
743 auto caller = CreatePeerConnectionWithAudioVideo();
744 auto callee = CreatePeerConnectionWithAudioVideo();
745
746 auto offer = caller->CreateOffer();
747 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
748 AddCandidateToFirstTransport(&candidate, offer.get());
749
750 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
751
752 RTCOfferAnswerOptions options;
753 options.ice_restart = true;
754 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer(options)));
755
756 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
757}
Steve Anton46d926a2018-01-23 10:23:06 -0800758TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700759 IceRestartOfferCandidateReplacesExistingCandidate) {
760 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
761 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
762
763 auto caller = CreatePeerConnectionWithAudioVideo();
764 auto callee = CreatePeerConnectionWithAudioVideo();
765
766 auto offer = caller->CreateOffer();
767 cricket::Candidate old_candidate =
768 CreateLocalUdpCandidate(kFirstCallerAddress);
769 AddCandidateToFirstTransport(&old_candidate, offer.get());
770
771 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
772
773 RTCOfferAnswerOptions options;
774 options.ice_restart = true;
775 auto restart_offer = caller->CreateOffer(options);
776 cricket::Candidate new_candidate =
777 CreateLocalUdpCandidate(kRestartedCallerAddress);
778 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
779
780 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
781
782 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
783 ASSERT_EQ(1u, remote_candidates.size());
784 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
785 remote_candidates[0]->candidate());
786}
787
788// Test that if there is not an ICE restart (i.e., nothing changes), then the
789// answer to a later offer should have the same ufrag/pwd as the first answer.
Steve Anton46d926a2018-01-23 10:23:06 -0800790TEST_P(PeerConnectionIceTest, LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700791 auto caller = CreatePeerConnectionWithAudioVideo();
792 auto callee = CreatePeerConnectionWithAudioVideo();
793
794 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
795 ASSERT_TRUE(
796 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
797
798 // Re-offer.
799 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
800
801 auto answer = callee->CreateAnswer();
802 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
803 auto* local_transport_desc =
804 GetFirstTransportDescription(callee->pc()->local_description());
805
806 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
807 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
808}
809
810// The following parameterized test verifies that if an offer is sent with a
811// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
812// other side has initiated an ICE restart and generate a new ufrag and pwd.
813// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
814// a=ice-pwd attributes compared to the previous SDP from the peer, it
815// indicates that ICE is restarting for this media stream."
816
Steve Anton46d926a2018-01-23 10:23:06 -0800817class PeerConnectionIceUfragPwdAnswerTest
818 : public PeerConnectionIceBaseTest,
819 public ::testing::WithParamInterface<
820 std::tuple<SdpSemantics, std::tuple<bool, bool>>> {
Steve Antonf1c6db12017-10-13 11:13:35 -0700821 protected:
Steve Anton46d926a2018-01-23 10:23:06 -0800822 PeerConnectionIceUfragPwdAnswerTest()
823 : PeerConnectionIceBaseTest(std::get<0>(GetParam())) {
824 auto param = std::get<1>(GetParam());
825 offer_new_ufrag_ = std::get<0>(param);
826 offer_new_pwd_ = std::get<1>(param);
Steve Antonf1c6db12017-10-13 11:13:35 -0700827 }
828
829 bool offer_new_ufrag_;
830 bool offer_new_pwd_;
831};
832
Steve Anton46d926a2018-01-23 10:23:06 -0800833TEST_P(PeerConnectionIceUfragPwdAnswerTest, TestIncludedInAnswer) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700834 auto caller = CreatePeerConnectionWithAudioVideo();
835 auto callee = CreatePeerConnectionWithAudioVideo();
836
837 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
838 ASSERT_TRUE(
839 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
840
841 auto offer = caller->CreateOffer();
842 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
843 if (offer_new_ufrag_) {
844 offer_transport_desc->ice_ufrag += "_new";
845 }
846 if (offer_new_pwd_) {
847 offer_transport_desc->ice_pwd += "_new";
848 }
849
850 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
851
852 auto answer = callee->CreateAnswer();
853 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
854 auto* local_transport_desc =
855 GetFirstTransportDescription(callee->pc()->local_description());
856
857 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
858 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
859}
860
861INSTANTIATE_TEST_CASE_P(
Steve Anton46d926a2018-01-23 10:23:06 -0800862 PeerConnectionIceTest,
863 PeerConnectionIceUfragPwdAnswerTest,
864 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
865 Values(std::make_pair(true, true), // Both changed.
866 std::make_pair(true, false), // Only ufrag changed.
867 std::make_pair(false, true)))); // Only pwd changed.
Steve Antonf1c6db12017-10-13 11:13:35 -0700868
869// Test that if an ICE restart is offered on one media section, then the answer
870// will only change ICE ufrag/pwd for that section and keep the other sections
871// the same.
872// Note that this only works if we have disabled BUNDLE, otherwise all media
873// sections will share the same transport.
Steve Anton46d926a2018-01-23 10:23:06 -0800874TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700875 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
876 auto caller = CreatePeerConnectionWithAudioVideo();
877 auto callee = CreatePeerConnectionWithAudioVideo();
878
879 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
880 ASSERT_TRUE(
881 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
882
883 RTCOfferAnswerOptions disable_bundle_options;
884 disable_bundle_options.use_rtp_mux = false;
885
886 auto offer = caller->CreateOffer(disable_bundle_options);
887
888 // Signal ICE restart on the first media section.
889 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
890 offer_transport_desc->ice_ufrag += "_new";
891 offer_transport_desc->ice_pwd += "_new";
892
893 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
894
895 auto answer = callee->CreateAnswer(disable_bundle_options);
896 const auto& answer_transports = answer->description()->transport_infos();
897 const auto& local_transports =
898 callee->pc()->local_description()->description()->transport_infos();
899
900 EXPECT_NE(answer_transports[0].description.ice_ufrag,
901 local_transports[0].description.ice_ufrag);
902 EXPECT_NE(answer_transports[0].description.ice_pwd,
903 local_transports[0].description.ice_pwd);
904 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
905 local_transports[1].description.ice_ufrag);
906 EXPECT_EQ(answer_transports[1].description.ice_pwd,
907 local_transports[1].description.ice_pwd);
908}
909
Qingsi Wange1692722017-11-29 13:27:20 -0800910// Test that when the initial offerer (caller) uses the lite implementation of
911// ICE and the callee uses the full implementation, the caller takes the
912// CONTROLLED role and the callee takes the CONTROLLING role. This is specified
913// in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -0800914TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -0800915 OfferFromLiteIceControlledAndAnswerFromFullIceControlling) {
916 auto caller = CreatePeerConnectionWithAudioVideo();
917 auto callee = CreatePeerConnectionWithAudioVideo();
918
919 auto offer = caller->CreateOffer();
920 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
921 ASSERT_TRUE(
922 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
923 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
924
925 auto answer = callee->CreateAnswer();
926 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_FULL);
927 ASSERT_TRUE(
928 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
929 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
930
931 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(caller));
932 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(callee));
933}
934
935// Test that when the caller and the callee both use the lite implementation of
936// ICE, the initial offerer (caller) takes the CONTROLLING role and the callee
937// takes the CONTROLLED role. This is specified in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -0800938TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -0800939 OfferFromLiteIceControllingAndAnswerFromLiteIceControlled) {
940 auto caller = CreatePeerConnectionWithAudioVideo();
941 auto callee = CreatePeerConnectionWithAudioVideo();
942
943 auto offer = caller->CreateOffer();
944 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
945 ASSERT_TRUE(
946 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
947 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
948
949 auto answer = callee->CreateAnswer();
950 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_LITE);
951 ASSERT_TRUE(
952 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
953 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
954
955 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(caller));
956 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(callee));
957}
958
Steve Anton46d926a2018-01-23 10:23:06 -0800959INSTANTIATE_TEST_CASE_P(PeerConnectionIceTest,
960 PeerConnectionIceTest,
961 Values(SdpSemantics::kPlanB,
962 SdpSemantics::kUnifiedPlan));
963
Qingsi Wang4ff54432018-03-01 18:25:20 -0800964class PeerConnectionIceConfigTest : public testing::Test {
965 protected:
966 void SetUp() override {
967 pc_factory_ = CreatePeerConnectionFactory(
968 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
969 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
Anders Carlsson67537952018-05-03 11:28:29 +0200970 CreateBuiltinAudioDecoderFactory(), CreateBuiltinVideoEncoderFactory(),
971 CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
972 nullptr /* audio_processing */);
Qingsi Wang4ff54432018-03-01 18:25:20 -0800973 }
974 void CreatePeerConnection(const RTCConfiguration& config) {
975 std::unique_ptr<cricket::FakePortAllocator> port_allocator(
976 new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr));
977 port_allocator_ = port_allocator.get();
978 rtc::scoped_refptr<PeerConnectionInterface> pc(
Niels Möllerf06f9232018-08-07 12:32:18 +0200979 pc_factory_->CreatePeerConnection(config, std::move(port_allocator),
980 nullptr /* cert_generator */,
981 &observer_));
Qingsi Wang4ff54432018-03-01 18:25:20 -0800982 EXPECT_TRUE(pc.get());
983 pc_ = std::move(pc.get());
984 }
985
986 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_ = nullptr;
987 rtc::scoped_refptr<PeerConnectionInterface> pc_ = nullptr;
988 cricket::FakePortAllocator* port_allocator_ = nullptr;
989
990 MockPeerConnectionObserver observer_;
991};
992
993TEST_F(PeerConnectionIceConfigTest, SetStunCandidateKeepaliveInterval) {
994 RTCConfiguration config;
995 config.stun_candidate_keepalive_interval = 123;
996 config.ice_candidate_pool_size = 1;
997 CreatePeerConnection(config);
998 ASSERT_NE(port_allocator_, nullptr);
Danil Chapovalov66cadcc2018-06-19 16:47:43 +0200999 absl::optional<int> actual_stun_keepalive_interval =
Qingsi Wang4ff54432018-03-01 18:25:20 -08001000 port_allocator_->stun_candidate_keepalive_interval();
1001 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 123);
1002 config.stun_candidate_keepalive_interval = 321;
1003 RTCError error;
1004 pc_->SetConfiguration(config, &error);
1005 actual_stun_keepalive_interval =
1006 port_allocator_->stun_candidate_keepalive_interval();
1007 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 321);
1008}
1009
Steve Antonf1c6db12017-10-13 11:13:35 -07001010} // namespace webrtc