blob: e015abffb8b9d6dc6481c4e972448a461f58cb33 [file] [log] [blame]
Steve Antonf1c6db12017-10-13 11:13:35 -07001/*
2 * Copyright 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "p2p/base/fakeportallocator.h"
12#include "p2p/base/teststunserver.h"
13#include "p2p/client/basicportallocator.h"
14#include "pc/mediasession.h"
Qingsi Wange1692722017-11-29 13:27:20 -080015#include "pc/peerconnection.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070016#include "pc/peerconnectionwrapper.h"
17#include "pc/sdputils.h"
18#ifdef WEBRTC_ANDROID
19#include "pc/test/androidtestinitializer.h"
20#endif
Karl Wiberg918f50c2018-07-05 11:40:33 +020021#include "absl/memory/memory.h"
Karl Wiberg1b0eae32017-10-17 14:48:54 +020022#include "api/audio_codecs/builtin_audio_decoder_factory.h"
23#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Qingsi Wange1692722017-11-29 13:27:20 -080024#include "api/peerconnectionproxy.h"
Yves Gerey2e00abc2018-10-05 15:39:24 +020025#include "api/umametrics.h"
Anders Carlsson67537952018-05-03 11:28:29 +020026#include "api/video_codecs/builtin_video_decoder_factory.h"
27#include "api/video_codecs/builtin_video_encoder_factory.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070028#include "pc/test/fakeaudiocapturemodule.h"
29#include "rtc_base/fakenetwork.h"
30#include "rtc_base/gunit.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020031#include "rtc_base/strings/string_builder.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070032#include "rtc_base/virtualsocketserver.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020033#include "system_wrappers/include/metrics.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070034
35namespace webrtc {
36
37using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
38using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
39using rtc::SocketAddress;
Steve Anton46d926a2018-01-23 10:23:06 -080040using ::testing::Combine;
Steve Antonf1c6db12017-10-13 11:13:35 -070041using ::testing::Values;
42
43constexpr int kIceCandidatesTimeout = 10000;
44
Steve Anton46d926a2018-01-23 10:23:06 -080045class PeerConnectionWrapperForIceTest : public PeerConnectionWrapper {
Steve Antonf1c6db12017-10-13 11:13:35 -070046 public:
47 using PeerConnectionWrapper::PeerConnectionWrapper;
48
49 // Adds a new ICE candidate to the first transport.
50 bool AddIceCandidate(cricket::Candidate* candidate) {
51 RTC_DCHECK(pc()->remote_description());
52 const auto* desc = pc()->remote_description()->description();
53 RTC_DCHECK(desc->contents().size() > 0);
54 const auto& first_content = desc->contents()[0];
55 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -070056 std::unique_ptr<IceCandidateInterface> jsep_candidate =
57 CreateIceCandidate(first_content.name, 0, *candidate);
58 return pc()->AddIceCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -070059 }
60
61 // Returns ICE candidates from the remote session description.
62 std::vector<const IceCandidateInterface*>
63 GetIceCandidatesFromRemoteDescription() {
64 const SessionDescriptionInterface* sdesc = pc()->remote_description();
65 RTC_DCHECK(sdesc);
66 std::vector<const IceCandidateInterface*> candidates;
67 for (size_t mline_index = 0; mline_index < sdesc->number_of_mediasections();
68 mline_index++) {
69 const auto* candidate_collection = sdesc->candidates(mline_index);
70 for (size_t i = 0; i < candidate_collection->count(); i++) {
71 candidates.push_back(candidate_collection->at(i));
72 }
73 }
74 return candidates;
75 }
76
77 rtc::FakeNetworkManager* network() { return network_; }
78
79 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
80
Jonas Oreland1cd39fa2018-10-11 07:47:12 +020081 // The port allocator used by this PC.
82 cricket::PortAllocator* port_allocator_;
83
Steve Antonf1c6db12017-10-13 11:13:35 -070084 private:
85 rtc::FakeNetworkManager* network_;
86};
87
Steve Anton46d926a2018-01-23 10:23:06 -080088class PeerConnectionIceBaseTest : public ::testing::Test {
Steve Antonf1c6db12017-10-13 11:13:35 -070089 protected:
Steve Anton46d926a2018-01-23 10:23:06 -080090 typedef std::unique_ptr<PeerConnectionWrapperForIceTest> WrapperPtr;
Steve Antonf1c6db12017-10-13 11:13:35 -070091
Steve Anton46d926a2018-01-23 10:23:06 -080092 explicit PeerConnectionIceBaseTest(SdpSemantics sdp_semantics)
93 : vss_(new rtc::VirtualSocketServer()),
94 main_(vss_.get()),
95 sdp_semantics_(sdp_semantics) {
Steve Antonf1c6db12017-10-13 11:13:35 -070096#ifdef WEBRTC_ANDROID
97 InitializeAndroidObjects();
98#endif
99 pc_factory_ = CreatePeerConnectionFactory(
100 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Anders Carlsson67537952018-05-03 11:28:29 +0200101 rtc::scoped_refptr<AudioDeviceModule>(FakeAudioCaptureModule::Create()),
102 CreateBuiltinAudioEncoderFactory(), CreateBuiltinAudioDecoderFactory(),
103 CreateBuiltinVideoEncoderFactory(), CreateBuiltinVideoDecoderFactory(),
104 nullptr /* audio_mixer */, nullptr /* audio_processing */);
Steve Antonf1c6db12017-10-13 11:13:35 -0700105 }
106
107 WrapperPtr CreatePeerConnection() {
108 return CreatePeerConnection(RTCConfiguration());
109 }
110
111 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
112 auto* fake_network = NewFakeNetwork();
113 auto port_allocator =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200114 absl::make_unique<cricket::BasicPortAllocator>(fake_network);
Steve Antonf1c6db12017-10-13 11:13:35 -0700115 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
116 cricket::PORTALLOCATOR_DISABLE_RELAY);
117 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
Steve Anton46d926a2018-01-23 10:23:06 -0800118 RTCConfiguration modified_config = config;
119 modified_config.sdp_semantics = sdp_semantics_;
Karl Wiberg918f50c2018-07-05 11:40:33 +0200120 auto observer = absl::make_unique<MockPeerConnectionObserver>();
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200121 auto port_allocator_copy = port_allocator.get();
Steve Antonf1c6db12017-10-13 11:13:35 -0700122 auto pc = pc_factory_->CreatePeerConnection(
Steve Anton46d926a2018-01-23 10:23:06 -0800123 modified_config, std::move(port_allocator), nullptr, observer.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700124 if (!pc) {
125 return nullptr;
126 }
127
Yves Gerey4e933292018-10-31 15:36:05 +0100128 observer->SetPeerConnectionInterface(pc.get());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200129 auto wrapper = absl::make_unique<PeerConnectionWrapperForIceTest>(
Steve Antonf1c6db12017-10-13 11:13:35 -0700130 pc_factory_, pc, std::move(observer));
131 wrapper->set_network(fake_network);
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200132 wrapper->port_allocator_ = port_allocator_copy;
Steve Antonf1c6db12017-10-13 11:13:35 -0700133 return wrapper;
134 }
135
136 // Accepts the same arguments as CreatePeerConnection and adds default audio
137 // and video tracks.
138 template <typename... Args>
139 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
140 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
141 if (!wrapper) {
142 return nullptr;
143 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700144 wrapper->AddAudioTrack("a");
145 wrapper->AddVideoTrack("v");
Steve Antonf1c6db12017-10-13 11:13:35 -0700146 return wrapper;
147 }
148
149 cricket::Candidate CreateLocalUdpCandidate(
150 const rtc::SocketAddress& address) {
151 cricket::Candidate candidate;
152 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
153 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
154 candidate.set_address(address);
155 candidate.set_type(cricket::LOCAL_PORT_TYPE);
156 return candidate;
157 }
158
159 // Remove all ICE ufrag/pwd lines from the given session description.
160 void RemoveIceUfragPwd(SessionDescriptionInterface* sdesc) {
161 SetIceUfragPwd(sdesc, "", "");
162 }
163
164 // Sets all ICE ufrag/pwds on the given session description.
165 void SetIceUfragPwd(SessionDescriptionInterface* sdesc,
166 const std::string& ufrag,
167 const std::string& pwd) {
168 auto* desc = sdesc->description();
169 for (const auto& content : desc->contents()) {
170 auto* transport_info = desc->GetTransportInfoByName(content.name);
171 transport_info->description.ice_ufrag = ufrag;
172 transport_info->description.ice_pwd = pwd;
173 }
174 }
175
Qingsi Wange1692722017-11-29 13:27:20 -0800176 // Set ICE mode on the given session description.
177 void SetIceMode(SessionDescriptionInterface* sdesc,
178 const cricket::IceMode ice_mode) {
179 auto* desc = sdesc->description();
180 for (const auto& content : desc->contents()) {
181 auto* transport_info = desc->GetTransportInfoByName(content.name);
182 transport_info->description.ice_mode = ice_mode;
183 }
184 }
185
Steve Antonf1c6db12017-10-13 11:13:35 -0700186 cricket::TransportDescription* GetFirstTransportDescription(
187 SessionDescriptionInterface* sdesc) {
188 auto* desc = sdesc->description();
189 RTC_DCHECK(desc->contents().size() > 0);
190 auto* transport_info =
191 desc->GetTransportInfoByName(desc->contents()[0].name);
192 RTC_DCHECK(transport_info);
193 return &transport_info->description;
194 }
195
196 const cricket::TransportDescription* GetFirstTransportDescription(
197 const SessionDescriptionInterface* sdesc) {
198 auto* desc = sdesc->description();
199 RTC_DCHECK(desc->contents().size() > 0);
200 auto* transport_info =
201 desc->GetTransportInfoByName(desc->contents()[0].name);
202 RTC_DCHECK(transport_info);
203 return &transport_info->description;
204 }
205
Qingsi Wange1692722017-11-29 13:27:20 -0800206 // TODO(qingsi): Rewrite this method in terms of the standard IceTransport
207 // after it is implemented.
208 cricket::IceRole GetIceRole(const WrapperPtr& pc_wrapper_ptr) {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100209 auto* pc_proxy =
210 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
211 pc_wrapper_ptr->pc());
212 PeerConnection* pc = static_cast<PeerConnection*>(pc_proxy->internal());
Steve Antonb8867112018-02-13 10:07:54 -0800213 for (auto transceiver : pc->GetTransceiversInternal()) {
Steve Anton69470252018-02-09 11:43:08 -0800214 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800215 // TODO(amithi): This test seems to be using a method that should not
216 // be public |rtp_packet_transport|. Because the test is not mocking
217 // the channels or transceiver, workaround will be to |static_cast|
218 // the channel until the method is rewritten.
219 cricket::BaseChannel* channel = static_cast<cricket::BaseChannel*>(
220 transceiver->internal()->channel());
Steve Anton46d926a2018-01-23 10:23:06 -0800221 if (channel) {
Zhi Huange830e682018-03-30 10:48:35 -0700222 auto dtls_transport = static_cast<cricket::DtlsTransportInternal*>(
223 channel->rtp_packet_transport());
224 return dtls_transport->ice_transport()->GetIceRole();
Steve Anton46d926a2018-01-23 10:23:06 -0800225 }
226 }
227 }
228 RTC_NOTREACHED();
229 return cricket::ICEROLE_UNKNOWN;
Qingsi Wange1692722017-11-29 13:27:20 -0800230 }
231
Steve Antonf1c6db12017-10-13 11:13:35 -0700232 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
233 SessionDescriptionInterface* sdesc) {
234 auto* desc = sdesc->description();
235 RTC_DCHECK(desc->contents().size() > 0);
236 const auto& first_content = desc->contents()[0];
237 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -0700238 std::unique_ptr<IceCandidateInterface> jsep_candidate =
239 CreateIceCandidate(first_content.name, 0, *candidate);
240 return sdesc->AddCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700241 }
242
243 rtc::FakeNetworkManager* NewFakeNetwork() {
244 // The PeerConnection's port allocator is tied to the PeerConnection's
245 // lifetime and expects the underlying NetworkManager to outlive it. That
246 // prevents us from having the PeerConnectionWrapper own the fake network.
247 // Therefore, the test fixture will own all the fake networks even though
248 // tests should access the fake network through the PeerConnectionWrapper.
249 auto* fake_network = new rtc::FakeNetworkManager();
250 fake_networks_.emplace_back(fake_network);
251 return fake_network;
252 }
253
254 std::unique_ptr<rtc::VirtualSocketServer> vss_;
255 rtc::AutoSocketServerThread main_;
256 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
257 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton46d926a2018-01-23 10:23:06 -0800258 const SdpSemantics sdp_semantics_;
259};
260
261class PeerConnectionIceTest
262 : public PeerConnectionIceBaseTest,
263 public ::testing::WithParamInterface<SdpSemantics> {
264 protected:
Harald Alvestrand76829d72018-07-18 23:24:36 +0200265 PeerConnectionIceTest() : PeerConnectionIceBaseTest(GetParam()) {
266 webrtc::metrics::Reset();
267 }
Steve Antonf1c6db12017-10-13 11:13:35 -0700268};
269
270::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
271 const char* b_expr,
272 const cricket::Candidate& a,
273 const cricket::Candidate& b) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200274 rtc::StringBuilder failure_info;
Steve Antonf1c6db12017-10-13 11:13:35 -0700275 if (a.component() != b.component()) {
276 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
277 }
278 if (a.protocol() != b.protocol()) {
279 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
280 }
281 if (a.address() != b.address()) {
282 failure_info << "\naddress: " << a.address().ToString()
283 << " != " << b.address().ToString();
284 }
285 if (a.type() != b.type()) {
286 failure_info << "\ntype: " << a.type() << " != " << b.type();
287 }
288 std::string failure_info_str = failure_info.str();
289 if (failure_info_str.empty()) {
290 return ::testing::AssertionSuccess();
291 } else {
292 return ::testing::AssertionFailure()
293 << a_expr << " and " << b_expr << " are not equal"
294 << failure_info_str;
295 }
296}
297
Steve Anton46d926a2018-01-23 10:23:06 -0800298TEST_P(PeerConnectionIceTest, OfferContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700299 const SocketAddress kLocalAddress("1.1.1.1", 0);
300
301 auto caller = CreatePeerConnectionWithAudioVideo();
302 caller->network()->AddInterface(kLocalAddress);
303
304 // Start ICE candidate gathering by setting the local offer.
305 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
306
307 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
308
309 auto offer = caller->CreateOffer();
310 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
311 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
312 offer->candidates(0)->count());
313 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
314 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
315 offer->candidates(1)->count());
316}
317
Steve Anton46d926a2018-01-23 10:23:06 -0800318TEST_P(PeerConnectionIceTest, AnswerContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700319 const SocketAddress kCallerAddress("1.1.1.1", 0);
320
321 auto caller = CreatePeerConnectionWithAudioVideo();
322 auto callee = CreatePeerConnectionWithAudioVideo();
323 caller->network()->AddInterface(kCallerAddress);
324
325 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
326 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
327
328 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
329
Steve Antondffead82018-02-06 10:31:29 -0800330 auto* answer = callee->pc()->local_description();
Steve Antonf1c6db12017-10-13 11:13:35 -0700331 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
332 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
333 answer->candidates(0)->count());
334 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
335 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
336 answer->candidates(1)->count());
337}
338
Steve Anton46d926a2018-01-23 10:23:06 -0800339TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700340 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
341 const SocketAddress kCallerAddress("1.1.1.1", 1111);
342
343 auto caller = CreatePeerConnectionWithAudioVideo();
344 auto callee = CreatePeerConnectionWithAudioVideo();
345
346 auto offer = caller->CreateOfferAndSetAsLocal();
347 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
348 AddCandidateToFirstTransport(&candidate, offer.get());
349
350 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
351 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
352 ASSERT_EQ(1u, remote_candidates.size());
353 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
354 remote_candidates[0]->candidate());
355}
356
Steve Anton46d926a2018-01-23 10:23:06 -0800357TEST_P(PeerConnectionIceTest, SetLocalDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700358 auto caller = CreatePeerConnectionWithAudioVideo();
359
360 auto offer = caller->CreateOffer();
361 RemoveIceUfragPwd(offer.get());
362
363 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
364}
365
Steve Anton46d926a2018-01-23 10:23:06 -0800366TEST_P(PeerConnectionIceTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700367 auto caller = CreatePeerConnectionWithAudioVideo();
368 auto callee = CreatePeerConnectionWithAudioVideo();
369
370 auto offer = caller->CreateOfferAndSetAsLocal();
371 RemoveIceUfragPwd(offer.get());
372
373 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
374}
375
Steve Antonf764cf42018-05-01 14:32:17 -0700376// Test that doing an offer/answer exchange with no transport (i.e., no data
377// channel or media) results in the ICE connection state staying at New.
378TEST_P(PeerConnectionIceTest,
379 OfferAnswerWithNoTransportsDoesNotChangeIceConnectionState) {
380 auto caller = CreatePeerConnection();
381 auto callee = CreatePeerConnection();
382
383 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
384
385 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
386 caller->pc()->ice_connection_state());
387 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
388 callee->pc()->ice_connection_state());
389}
390
Steve Antonf1c6db12017-10-13 11:13:35 -0700391// The following group tests that ICE candidates are not generated before
392// SetLocalDescription is called on a PeerConnection.
393
Steve Anton46d926a2018-01-23 10:23:06 -0800394TEST_P(PeerConnectionIceTest, NoIceCandidatesBeforeSetLocalDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700395 const SocketAddress kLocalAddress("1.1.1.1", 0);
396
397 auto caller = CreatePeerConnectionWithAudioVideo();
398 caller->network()->AddInterface(kLocalAddress);
399
400 // Pump for 1 second and verify that no candidates are generated.
401 rtc::Thread::Current()->ProcessMessages(1000);
402
403 EXPECT_EQ(0u, caller->observer()->candidates_.size());
404}
Steve Anton46d926a2018-01-23 10:23:06 -0800405TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700406 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
407 const SocketAddress kCallerAddress("1.1.1.1", 1111);
408
409 auto caller = CreatePeerConnectionWithAudioVideo();
410 auto callee = CreatePeerConnectionWithAudioVideo();
411 caller->network()->AddInterface(kCallerAddress);
412
413 auto offer = caller->CreateOfferAndSetAsLocal();
414 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
415 AddCandidateToFirstTransport(&candidate, offer.get());
416 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
417
418 // Pump for 1 second and verify that no candidates are generated.
419 rtc::Thread::Current()->ProcessMessages(1000);
420
421 EXPECT_EQ(0u, callee->observer()->candidates_.size());
422}
423
Steve Anton46d926a2018-01-23 10:23:06 -0800424TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenRemoteDescriptionNotSet) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700425 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
426
427 auto caller = CreatePeerConnectionWithAudioVideo();
428 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton27ab0e52018-07-23 15:11:53 -0700429 std::unique_ptr<IceCandidateInterface> jsep_candidate =
430 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
Steve Antonf1c6db12017-10-13 11:13:35 -0700431
Steve Anton27ab0e52018-07-23 15:11:53 -0700432 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700433
434 caller->CreateOfferAndSetAsLocal();
435
Steve Anton27ab0e52018-07-23 15:11:53 -0700436 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Harald Alvestrand76829d72018-07-18 23:24:36 +0200437 EXPECT_EQ(
438 2, webrtc::metrics::NumSamples("WebRTC.PeerConnection.AddIceCandidate"));
439 EXPECT_EQ(
440 2, webrtc::metrics::NumEvents("WebRTC.PeerConnection.AddIceCandidate",
441 kAddIceCandidateFailNoRemoteDescription));
Steve Antonf1c6db12017-10-13 11:13:35 -0700442}
443
Steve Antonc79268f2018-04-24 09:54:10 -0700444TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenPeerConnectionClosed) {
445 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
446
447 auto caller = CreatePeerConnectionWithAudioVideo();
448 auto callee = CreatePeerConnectionWithAudioVideo();
449
450 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
451
452 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
453 auto* audio_content = cricket::GetFirstAudioContent(
454 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700455 std::unique_ptr<IceCandidateInterface> jsep_candidate =
456 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700457
458 caller->pc()->Close();
459
Steve Anton27ab0e52018-07-23 15:11:53 -0700460 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700461}
462
Steve Anton46d926a2018-01-23 10:23:06 -0800463TEST_P(PeerConnectionIceTest, DuplicateIceCandidateIgnoredWhenAdded) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700464 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
465
466 auto caller = CreatePeerConnectionWithAudioVideo();
467 auto callee = CreatePeerConnectionWithAudioVideo();
468
469 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
470 ASSERT_TRUE(
471 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
472
473 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
474 caller->AddIceCandidate(&candidate);
475 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
476 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
477}
478
Steve Anton46d926a2018-01-23 10:23:06 -0800479TEST_P(PeerConnectionIceTest,
Steve Antonc79268f2018-04-24 09:54:10 -0700480 CannotRemoveIceCandidatesWhenPeerConnectionClosed) {
481 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
482
483 auto caller = CreatePeerConnectionWithAudioVideo();
484 auto callee = CreatePeerConnectionWithAudioVideo();
485
486 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
487
488 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
489 auto* audio_content = cricket::GetFirstAudioContent(
490 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700491 std::unique_ptr<IceCandidateInterface> ice_candidate =
492 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700493
Steve Anton27ab0e52018-07-23 15:11:53 -0700494 ASSERT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700495
496 caller->pc()->Close();
497
498 EXPECT_FALSE(caller->pc()->RemoveIceCandidates({candidate}));
499}
500
501TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700502 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
503 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
504
505 auto caller = CreatePeerConnectionWithAudioVideo();
506 auto callee = CreatePeerConnectionWithAudioVideo();
507
508 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
509 ASSERT_TRUE(
510 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
511
512 // |candidate.transport_name()| is empty.
513 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton46d926a2018-01-23 10:23:06 -0800514 auto* audio_content = cricket::GetFirstAudioContent(
515 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700516 std::unique_ptr<IceCandidateInterface> ice_candidate =
517 CreateIceCandidate(audio_content->name, 0, candidate);
518 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700519 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
520}
521
Steve Anton46d926a2018-01-23 10:23:06 -0800522TEST_P(PeerConnectionIceTest, RemoveCandidateRemovesFromRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700523 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
524
525 auto caller = CreatePeerConnectionWithAudioVideo();
526 auto callee = CreatePeerConnectionWithAudioVideo();
527
528 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
529 ASSERT_TRUE(
530 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
531
532 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
533 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
534 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
535 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
536}
537
538// Test that if a candidate is added via AddIceCandidate and via an updated
539// remote description, then both candidates appear in the stored remote
540// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800541TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700542 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
543 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
544 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
545
546 auto caller = CreatePeerConnectionWithAudioVideo();
547 auto callee = CreatePeerConnectionWithAudioVideo();
548
549 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
550 ASSERT_TRUE(
551 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
552
553 // Add one candidate via |AddIceCandidate|.
554 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
555 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
556
557 // Add the second candidate via a reoffer.
558 auto offer = caller->CreateOffer();
559 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
560 AddCandidateToFirstTransport(&candidate2, offer.get());
561
562 // Expect both candidates to appear in the callee's remote description.
563 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
564 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
565}
566
567// The follow test verifies that SetLocal/RemoteDescription fails when an offer
568// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
569// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
570// pwd must be 22-256 characters and ufrag must be 4-256 characters.
Steve Anton46d926a2018-01-23 10:23:06 -0800571TEST_P(PeerConnectionIceTest, VerifyUfragPwdLength) {
Yves Gerey665174f2018-06-19 15:03:05 +0200572 auto set_local_description_with_ufrag_pwd_length = [this](int ufrag_len,
573 int pwd_len) {
574 auto pc = CreatePeerConnectionWithAudioVideo();
575 auto offer = pc->CreateOffer();
576 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
577 std::string(pwd_len, 'x'));
578 return pc->SetLocalDescription(std::move(offer));
579 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700580
Yves Gerey665174f2018-06-19 15:03:05 +0200581 auto set_remote_description_with_ufrag_pwd_length = [this](int ufrag_len,
582 int pwd_len) {
583 auto pc = CreatePeerConnectionWithAudioVideo();
584 auto offer = pc->CreateOffer();
585 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
586 std::string(pwd_len, 'x'));
587 return pc->SetRemoteDescription(std::move(offer));
588 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700589
590 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
591 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
592 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
593 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
594 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
595 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
596 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
597 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
598 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
599 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
600 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
601 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
602}
603
604::testing::AssertionResult AssertIpInCandidates(
605 const char* address_expr,
606 const char* candidates_expr,
607 const SocketAddress& address,
608 const std::vector<IceCandidateInterface*> candidates) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200609 rtc::StringBuilder candidate_hosts;
Steve Antonf1c6db12017-10-13 11:13:35 -0700610 for (const auto* candidate : candidates) {
611 const auto& candidate_ip = candidate->candidate().address().ipaddr();
612 if (candidate_ip == address.ipaddr()) {
613 return ::testing::AssertionSuccess();
614 }
Jonas Olssonabbe8412018-04-03 13:40:05 +0200615 candidate_hosts << "\n" << candidate_ip.ToString();
Steve Antonf1c6db12017-10-13 11:13:35 -0700616 }
617 return ::testing::AssertionFailure()
618 << address_expr << " (host " << address.HostAsURIString()
619 << ") not in " << candidates_expr
620 << " which have the following address hosts:" << candidate_hosts.str();
621}
622
Steve Anton46d926a2018-01-23 10:23:06 -0800623TEST_P(PeerConnectionIceTest, CandidatesGeneratedForEachLocalInterface) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700624 const SocketAddress kLocalAddress1("1.1.1.1", 0);
625 const SocketAddress kLocalAddress2("2.2.2.2", 0);
626
627 auto caller = CreatePeerConnectionWithAudioVideo();
628 caller->network()->AddInterface(kLocalAddress1);
629 caller->network()->AddInterface(kLocalAddress2);
630
631 caller->CreateOfferAndSetAsLocal();
632 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
633
634 auto candidates = caller->observer()->GetCandidatesByMline(0);
635 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
636 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
637}
638
Steve Anton46d926a2018-01-23 10:23:06 -0800639TEST_P(PeerConnectionIceTest, TrickledSingleCandidateAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700640 const SocketAddress kCallerAddress("1.1.1.1", 1111);
641
642 auto caller = CreatePeerConnectionWithAudioVideo();
643 auto callee = CreatePeerConnectionWithAudioVideo();
644
645 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
646
647 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
648 callee->AddIceCandidate(&candidate);
649 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
650 ASSERT_EQ(1u, candidates.size());
651 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
652 candidates[0]->candidate());
653}
654
Steve Anton46d926a2018-01-23 10:23:06 -0800655TEST_P(PeerConnectionIceTest, TwoTrickledCandidatesAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700656 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
657 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
658
659 auto caller = CreatePeerConnectionWithAudioVideo();
660 auto callee = CreatePeerConnectionWithAudioVideo();
661
662 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
663 ASSERT_TRUE(
664 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
665
666 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
667 caller->AddIceCandidate(&candidate1);
668
669 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
670 caller->AddIceCandidate(&candidate2);
671
672 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
673 ASSERT_EQ(2u, candidates.size());
674 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
675 candidates[0]->candidate());
676 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
677 candidates[1]->candidate());
678}
679
Steve Anton46d926a2018-01-23 10:23:06 -0800680TEST_P(PeerConnectionIceTest, LocalDescriptionUpdatedWhenContinualGathering) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700681 const SocketAddress kLocalAddress("1.1.1.1", 0);
682
683 RTCConfiguration config;
684 config.continual_gathering_policy =
685 PeerConnectionInterface::GATHER_CONTINUALLY;
686 auto caller = CreatePeerConnectionWithAudioVideo(config);
687 caller->network()->AddInterface(kLocalAddress);
688
689 // Start ICE candidate gathering by setting the local offer.
690 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
691
692 // Since we're using continual gathering, we won't get "gathering done".
693 EXPECT_TRUE_WAIT(
694 caller->pc()->local_description()->candidates(0)->count() > 0,
695 kIceCandidatesTimeout);
696}
697
698// Test that when continual gathering is enabled, and a network interface goes
699// down, the candidate is signaled as removed and removed from the local
700// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800701TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700702 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
703 const SocketAddress kLocalAddress("1.1.1.1", 0);
704
705 RTCConfiguration config;
706 config.continual_gathering_policy =
707 PeerConnectionInterface::GATHER_CONTINUALLY;
708 auto caller = CreatePeerConnectionWithAudioVideo(config);
709 caller->network()->AddInterface(kLocalAddress);
710
711 // Start ICE candidate gathering by setting the local offer.
712 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
713
714 EXPECT_TRUE_WAIT(
715 caller->pc()->local_description()->candidates(0)->count() > 0,
716 kIceCandidatesTimeout);
717
718 // Remove the only network interface, causing the PeerConnection to signal
719 // the removal of all candidates derived from this interface.
720 caller->network()->RemoveInterface(kLocalAddress);
721
722 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
723 kIceCandidatesTimeout);
724 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
725}
726
Steve Anton46d926a2018-01-23 10:23:06 -0800727TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700728 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
729 const SocketAddress kLocalAddress("1.1.1.1", 0);
730
731 RTCConfiguration config;
732 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
733 auto caller = CreatePeerConnectionWithAudioVideo(config);
734 caller->network()->AddInterface(kLocalAddress);
735
736 // Start ICE candidate gathering by setting the local offer.
737 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
738
739 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
740
741 caller->network()->RemoveInterface(kLocalAddress);
742
743 // Verify that the local candidates are not removed;
744 rtc::Thread::Current()->ProcessMessages(1000);
745 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
746}
747
748// The following group tests that when an offer includes a new ufrag or pwd
749// (indicating an ICE restart) the old candidates are removed and new candidates
750// added to the remote description.
751
Steve Anton46d926a2018-01-23 10:23:06 -0800752TEST_P(PeerConnectionIceTest, IceRestartOfferClearsExistingCandidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700753 const SocketAddress kCallerAddress("1.1.1.1", 1111);
754
755 auto caller = CreatePeerConnectionWithAudioVideo();
756 auto callee = CreatePeerConnectionWithAudioVideo();
757
758 auto offer = caller->CreateOffer();
759 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
760 AddCandidateToFirstTransport(&candidate, offer.get());
761
762 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
763
764 RTCOfferAnswerOptions options;
765 options.ice_restart = true;
766 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer(options)));
767
768 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
769}
Steve Anton46d926a2018-01-23 10:23:06 -0800770TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700771 IceRestartOfferCandidateReplacesExistingCandidate) {
772 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
773 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
774
775 auto caller = CreatePeerConnectionWithAudioVideo();
776 auto callee = CreatePeerConnectionWithAudioVideo();
777
778 auto offer = caller->CreateOffer();
779 cricket::Candidate old_candidate =
780 CreateLocalUdpCandidate(kFirstCallerAddress);
781 AddCandidateToFirstTransport(&old_candidate, offer.get());
782
783 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
784
785 RTCOfferAnswerOptions options;
786 options.ice_restart = true;
787 auto restart_offer = caller->CreateOffer(options);
788 cricket::Candidate new_candidate =
789 CreateLocalUdpCandidate(kRestartedCallerAddress);
790 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
791
792 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
793
794 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
795 ASSERT_EQ(1u, remote_candidates.size());
796 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
797 remote_candidates[0]->candidate());
798}
799
800// Test that if there is not an ICE restart (i.e., nothing changes), then the
801// answer to a later offer should have the same ufrag/pwd as the first answer.
Steve Anton46d926a2018-01-23 10:23:06 -0800802TEST_P(PeerConnectionIceTest, LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700803 auto caller = CreatePeerConnectionWithAudioVideo();
804 auto callee = CreatePeerConnectionWithAudioVideo();
805
806 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
807 ASSERT_TRUE(
808 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
809
810 // Re-offer.
811 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
812
813 auto answer = callee->CreateAnswer();
814 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
815 auto* local_transport_desc =
816 GetFirstTransportDescription(callee->pc()->local_description());
817
818 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
819 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
820}
821
822// The following parameterized test verifies that if an offer is sent with a
823// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
824// other side has initiated an ICE restart and generate a new ufrag and pwd.
825// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
826// a=ice-pwd attributes compared to the previous SDP from the peer, it
827// indicates that ICE is restarting for this media stream."
828
Steve Anton46d926a2018-01-23 10:23:06 -0800829class PeerConnectionIceUfragPwdAnswerTest
830 : public PeerConnectionIceBaseTest,
831 public ::testing::WithParamInterface<
832 std::tuple<SdpSemantics, std::tuple<bool, bool>>> {
Steve Antonf1c6db12017-10-13 11:13:35 -0700833 protected:
Steve Anton46d926a2018-01-23 10:23:06 -0800834 PeerConnectionIceUfragPwdAnswerTest()
835 : PeerConnectionIceBaseTest(std::get<0>(GetParam())) {
836 auto param = std::get<1>(GetParam());
837 offer_new_ufrag_ = std::get<0>(param);
838 offer_new_pwd_ = std::get<1>(param);
Steve Antonf1c6db12017-10-13 11:13:35 -0700839 }
840
841 bool offer_new_ufrag_;
842 bool offer_new_pwd_;
843};
844
Steve Anton46d926a2018-01-23 10:23:06 -0800845TEST_P(PeerConnectionIceUfragPwdAnswerTest, TestIncludedInAnswer) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700846 auto caller = CreatePeerConnectionWithAudioVideo();
847 auto callee = CreatePeerConnectionWithAudioVideo();
848
849 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
850 ASSERT_TRUE(
851 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
852
853 auto offer = caller->CreateOffer();
854 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
855 if (offer_new_ufrag_) {
856 offer_transport_desc->ice_ufrag += "_new";
857 }
858 if (offer_new_pwd_) {
859 offer_transport_desc->ice_pwd += "_new";
860 }
861
862 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
863
864 auto answer = callee->CreateAnswer();
865 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
866 auto* local_transport_desc =
867 GetFirstTransportDescription(callee->pc()->local_description());
868
869 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
870 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
871}
872
873INSTANTIATE_TEST_CASE_P(
Steve Anton46d926a2018-01-23 10:23:06 -0800874 PeerConnectionIceTest,
875 PeerConnectionIceUfragPwdAnswerTest,
876 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
877 Values(std::make_pair(true, true), // Both changed.
878 std::make_pair(true, false), // Only ufrag changed.
879 std::make_pair(false, true)))); // Only pwd changed.
Steve Antonf1c6db12017-10-13 11:13:35 -0700880
881// Test that if an ICE restart is offered on one media section, then the answer
882// will only change ICE ufrag/pwd for that section and keep the other sections
883// the same.
884// Note that this only works if we have disabled BUNDLE, otherwise all media
885// sections will share the same transport.
Steve Anton46d926a2018-01-23 10:23:06 -0800886TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700887 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
888 auto caller = CreatePeerConnectionWithAudioVideo();
889 auto callee = CreatePeerConnectionWithAudioVideo();
890
891 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
892 ASSERT_TRUE(
893 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
894
895 RTCOfferAnswerOptions disable_bundle_options;
896 disable_bundle_options.use_rtp_mux = false;
897
898 auto offer = caller->CreateOffer(disable_bundle_options);
899
900 // Signal ICE restart on the first media section.
901 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
902 offer_transport_desc->ice_ufrag += "_new";
903 offer_transport_desc->ice_pwd += "_new";
904
905 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
906
907 auto answer = callee->CreateAnswer(disable_bundle_options);
908 const auto& answer_transports = answer->description()->transport_infos();
909 const auto& local_transports =
910 callee->pc()->local_description()->description()->transport_infos();
911
912 EXPECT_NE(answer_transports[0].description.ice_ufrag,
913 local_transports[0].description.ice_ufrag);
914 EXPECT_NE(answer_transports[0].description.ice_pwd,
915 local_transports[0].description.ice_pwd);
916 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
917 local_transports[1].description.ice_ufrag);
918 EXPECT_EQ(answer_transports[1].description.ice_pwd,
919 local_transports[1].description.ice_pwd);
920}
921
Qingsi Wange1692722017-11-29 13:27:20 -0800922// Test that when the initial offerer (caller) uses the lite implementation of
923// ICE and the callee uses the full implementation, the caller takes the
924// CONTROLLED role and the callee takes the CONTROLLING role. This is specified
925// in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -0800926TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -0800927 OfferFromLiteIceControlledAndAnswerFromFullIceControlling) {
928 auto caller = CreatePeerConnectionWithAudioVideo();
929 auto callee = CreatePeerConnectionWithAudioVideo();
930
931 auto offer = caller->CreateOffer();
932 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
933 ASSERT_TRUE(
934 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
935 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
936
937 auto answer = callee->CreateAnswer();
938 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_FULL);
939 ASSERT_TRUE(
940 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
941 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
942
943 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(caller));
944 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(callee));
945}
946
947// Test that when the caller and the callee both use the lite implementation of
948// ICE, the initial offerer (caller) takes the CONTROLLING role and the callee
949// takes the CONTROLLED role. This is specified in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -0800950TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -0800951 OfferFromLiteIceControllingAndAnswerFromLiteIceControlled) {
952 auto caller = CreatePeerConnectionWithAudioVideo();
953 auto callee = CreatePeerConnectionWithAudioVideo();
954
955 auto offer = caller->CreateOffer();
956 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
957 ASSERT_TRUE(
958 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
959 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
960
961 auto answer = callee->CreateAnswer();
962 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_LITE);
963 ASSERT_TRUE(
964 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
965 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
966
967 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(caller));
968 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(callee));
969}
970
Steve Anton46d926a2018-01-23 10:23:06 -0800971INSTANTIATE_TEST_CASE_P(PeerConnectionIceTest,
972 PeerConnectionIceTest,
973 Values(SdpSemantics::kPlanB,
974 SdpSemantics::kUnifiedPlan));
975
Qingsi Wang4ff54432018-03-01 18:25:20 -0800976class PeerConnectionIceConfigTest : public testing::Test {
977 protected:
978 void SetUp() override {
979 pc_factory_ = CreatePeerConnectionFactory(
980 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
981 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
Anders Carlsson67537952018-05-03 11:28:29 +0200982 CreateBuiltinAudioDecoderFactory(), CreateBuiltinVideoEncoderFactory(),
983 CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
984 nullptr /* audio_processing */);
Qingsi Wang4ff54432018-03-01 18:25:20 -0800985 }
986 void CreatePeerConnection(const RTCConfiguration& config) {
987 std::unique_ptr<cricket::FakePortAllocator> port_allocator(
988 new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr));
989 port_allocator_ = port_allocator.get();
990 rtc::scoped_refptr<PeerConnectionInterface> pc(
Niels Möllerf06f9232018-08-07 12:32:18 +0200991 pc_factory_->CreatePeerConnection(config, std::move(port_allocator),
992 nullptr /* cert_generator */,
993 &observer_));
Qingsi Wang4ff54432018-03-01 18:25:20 -0800994 EXPECT_TRUE(pc.get());
995 pc_ = std::move(pc.get());
996 }
997
998 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_ = nullptr;
999 rtc::scoped_refptr<PeerConnectionInterface> pc_ = nullptr;
1000 cricket::FakePortAllocator* port_allocator_ = nullptr;
1001
1002 MockPeerConnectionObserver observer_;
1003};
1004
1005TEST_F(PeerConnectionIceConfigTest, SetStunCandidateKeepaliveInterval) {
1006 RTCConfiguration config;
1007 config.stun_candidate_keepalive_interval = 123;
1008 config.ice_candidate_pool_size = 1;
1009 CreatePeerConnection(config);
1010 ASSERT_NE(port_allocator_, nullptr);
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001011 absl::optional<int> actual_stun_keepalive_interval =
Qingsi Wang4ff54432018-03-01 18:25:20 -08001012 port_allocator_->stun_candidate_keepalive_interval();
1013 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 123);
1014 config.stun_candidate_keepalive_interval = 321;
1015 RTCError error;
1016 pc_->SetConfiguration(config, &error);
1017 actual_stun_keepalive_interval =
1018 port_allocator_->stun_candidate_keepalive_interval();
1019 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 321);
1020}
1021
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001022TEST_P(PeerConnectionIceTest, IceCredentialsCreateOffer) {
1023 RTCConfiguration config;
1024 config.ice_candidate_pool_size = 1;
1025 auto pc = CreatePeerConnectionWithAudioVideo(config);
1026 ASSERT_NE(pc->port_allocator_, nullptr);
1027 auto offer = pc->CreateOffer();
1028 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1029 ASSERT_EQ(1u, credentials.size());
1030
1031 auto* desc = offer->description();
1032 for (const auto& content : desc->contents()) {
1033 auto* transport_info = desc->GetTransportInfoByName(content.name);
1034 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1035 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1036 }
1037}
1038
1039TEST_P(PeerConnectionIceTest, IceCredentialsCreateAnswer) {
1040 RTCConfiguration config;
1041 config.ice_candidate_pool_size = 1;
1042 auto pc = CreatePeerConnectionWithAudioVideo(config);
1043 ASSERT_NE(pc->port_allocator_, nullptr);
1044 auto offer = pc->CreateOffer();
1045 ASSERT_TRUE(pc->SetRemoteDescription(std::move(offer)));
1046 auto answer = pc->CreateAnswer();
1047
1048 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1049 ASSERT_EQ(1u, credentials.size());
1050
1051 auto* desc = answer->description();
1052 for (const auto& content : desc->contents()) {
1053 auto* transport_info = desc->GetTransportInfoByName(content.name);
1054 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1055 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1056 }
1057}
1058
Steve Antonf1c6db12017-10-13 11:13:35 -07001059} // namespace webrtc