blob: 928549f3800f2564fe9b674c2d4c6f805ef0aa92 [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"
Mirko Bonadei2ff3f492018-11-22 09:00:13 +010024#include "api/create_peerconnection_factory.h"
Qingsi Wange1692722017-11-29 13:27:20 -080025#include "api/peerconnectionproxy.h"
Yves Gerey2e00abc2018-10-05 15:39:24 +020026#include "api/umametrics.h"
Anders Carlsson67537952018-05-03 11:28:29 +020027#include "api/video_codecs/builtin_video_decoder_factory.h"
28#include "api/video_codecs/builtin_video_encoder_factory.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070029#include "pc/test/fakeaudiocapturemodule.h"
30#include "rtc_base/fakenetwork.h"
31#include "rtc_base/gunit.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020032#include "rtc_base/strings/string_builder.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070033#include "rtc_base/virtualsocketserver.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020034#include "system_wrappers/include/metrics.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070035
36namespace webrtc {
37
38using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
39using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
40using rtc::SocketAddress;
Steve Anton46d926a2018-01-23 10:23:06 -080041using ::testing::Combine;
Steve Antonf1c6db12017-10-13 11:13:35 -070042using ::testing::Values;
43
44constexpr int kIceCandidatesTimeout = 10000;
45
Steve Anton46d926a2018-01-23 10:23:06 -080046class PeerConnectionWrapperForIceTest : public PeerConnectionWrapper {
Steve Antonf1c6db12017-10-13 11:13:35 -070047 public:
48 using PeerConnectionWrapper::PeerConnectionWrapper;
49
50 // Adds a new ICE candidate to the first transport.
51 bool AddIceCandidate(cricket::Candidate* candidate) {
52 RTC_DCHECK(pc()->remote_description());
53 const auto* desc = pc()->remote_description()->description();
54 RTC_DCHECK(desc->contents().size() > 0);
55 const auto& first_content = desc->contents()[0];
56 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -070057 std::unique_ptr<IceCandidateInterface> jsep_candidate =
58 CreateIceCandidate(first_content.name, 0, *candidate);
59 return pc()->AddIceCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -070060 }
61
62 // Returns ICE candidates from the remote session description.
63 std::vector<const IceCandidateInterface*>
64 GetIceCandidatesFromRemoteDescription() {
65 const SessionDescriptionInterface* sdesc = pc()->remote_description();
66 RTC_DCHECK(sdesc);
67 std::vector<const IceCandidateInterface*> candidates;
68 for (size_t mline_index = 0; mline_index < sdesc->number_of_mediasections();
69 mline_index++) {
70 const auto* candidate_collection = sdesc->candidates(mline_index);
71 for (size_t i = 0; i < candidate_collection->count(); i++) {
72 candidates.push_back(candidate_collection->at(i));
73 }
74 }
75 return candidates;
76 }
77
78 rtc::FakeNetworkManager* network() { return network_; }
79
80 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
81
Jonas Oreland1cd39fa2018-10-11 07:47:12 +020082 // The port allocator used by this PC.
83 cricket::PortAllocator* port_allocator_;
84
Steve Antonf1c6db12017-10-13 11:13:35 -070085 private:
86 rtc::FakeNetworkManager* network_;
87};
88
Steve Anton46d926a2018-01-23 10:23:06 -080089class PeerConnectionIceBaseTest : public ::testing::Test {
Steve Antonf1c6db12017-10-13 11:13:35 -070090 protected:
Steve Anton46d926a2018-01-23 10:23:06 -080091 typedef std::unique_ptr<PeerConnectionWrapperForIceTest> WrapperPtr;
Steve Antonf1c6db12017-10-13 11:13:35 -070092
Steve Anton46d926a2018-01-23 10:23:06 -080093 explicit PeerConnectionIceBaseTest(SdpSemantics sdp_semantics)
94 : vss_(new rtc::VirtualSocketServer()),
95 main_(vss_.get()),
96 sdp_semantics_(sdp_semantics) {
Steve Antonf1c6db12017-10-13 11:13:35 -070097#ifdef WEBRTC_ANDROID
98 InitializeAndroidObjects();
99#endif
100 pc_factory_ = CreatePeerConnectionFactory(
101 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Anders Carlsson67537952018-05-03 11:28:29 +0200102 rtc::scoped_refptr<AudioDeviceModule>(FakeAudioCaptureModule::Create()),
103 CreateBuiltinAudioEncoderFactory(), CreateBuiltinAudioDecoderFactory(),
104 CreateBuiltinVideoEncoderFactory(), CreateBuiltinVideoDecoderFactory(),
105 nullptr /* audio_mixer */, nullptr /* audio_processing */);
Steve Antonf1c6db12017-10-13 11:13:35 -0700106 }
107
108 WrapperPtr CreatePeerConnection() {
109 return CreatePeerConnection(RTCConfiguration());
110 }
111
112 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
113 auto* fake_network = NewFakeNetwork();
114 auto port_allocator =
Karl Wiberg918f50c2018-07-05 11:40:33 +0200115 absl::make_unique<cricket::BasicPortAllocator>(fake_network);
Steve Antonf1c6db12017-10-13 11:13:35 -0700116 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
117 cricket::PORTALLOCATOR_DISABLE_RELAY);
118 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
Steve Anton46d926a2018-01-23 10:23:06 -0800119 RTCConfiguration modified_config = config;
120 modified_config.sdp_semantics = sdp_semantics_;
Karl Wiberg918f50c2018-07-05 11:40:33 +0200121 auto observer = absl::make_unique<MockPeerConnectionObserver>();
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200122 auto port_allocator_copy = port_allocator.get();
Steve Antonf1c6db12017-10-13 11:13:35 -0700123 auto pc = pc_factory_->CreatePeerConnection(
Steve Anton46d926a2018-01-23 10:23:06 -0800124 modified_config, std::move(port_allocator), nullptr, observer.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700125 if (!pc) {
126 return nullptr;
127 }
128
Yves Gerey4e933292018-10-31 15:36:05 +0100129 observer->SetPeerConnectionInterface(pc.get());
Karl Wiberg918f50c2018-07-05 11:40:33 +0200130 auto wrapper = absl::make_unique<PeerConnectionWrapperForIceTest>(
Steve Antonf1c6db12017-10-13 11:13:35 -0700131 pc_factory_, pc, std::move(observer));
132 wrapper->set_network(fake_network);
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200133 wrapper->port_allocator_ = port_allocator_copy;
Steve Antonf1c6db12017-10-13 11:13:35 -0700134 return wrapper;
135 }
136
137 // Accepts the same arguments as CreatePeerConnection and adds default audio
138 // and video tracks.
139 template <typename... Args>
140 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
141 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
142 if (!wrapper) {
143 return nullptr;
144 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700145 wrapper->AddAudioTrack("a");
146 wrapper->AddVideoTrack("v");
Steve Antonf1c6db12017-10-13 11:13:35 -0700147 return wrapper;
148 }
149
150 cricket::Candidate CreateLocalUdpCandidate(
151 const rtc::SocketAddress& address) {
152 cricket::Candidate candidate;
153 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
154 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
155 candidate.set_address(address);
156 candidate.set_type(cricket::LOCAL_PORT_TYPE);
157 return candidate;
158 }
159
160 // Remove all ICE ufrag/pwd lines from the given session description.
161 void RemoveIceUfragPwd(SessionDescriptionInterface* sdesc) {
162 SetIceUfragPwd(sdesc, "", "");
163 }
164
165 // Sets all ICE ufrag/pwds on the given session description.
166 void SetIceUfragPwd(SessionDescriptionInterface* sdesc,
167 const std::string& ufrag,
168 const std::string& pwd) {
169 auto* desc = sdesc->description();
170 for (const auto& content : desc->contents()) {
171 auto* transport_info = desc->GetTransportInfoByName(content.name);
172 transport_info->description.ice_ufrag = ufrag;
173 transport_info->description.ice_pwd = pwd;
174 }
175 }
176
Qingsi Wange1692722017-11-29 13:27:20 -0800177 // Set ICE mode on the given session description.
178 void SetIceMode(SessionDescriptionInterface* sdesc,
179 const cricket::IceMode ice_mode) {
180 auto* desc = sdesc->description();
181 for (const auto& content : desc->contents()) {
182 auto* transport_info = desc->GetTransportInfoByName(content.name);
183 transport_info->description.ice_mode = ice_mode;
184 }
185 }
186
Steve Antonf1c6db12017-10-13 11:13:35 -0700187 cricket::TransportDescription* GetFirstTransportDescription(
188 SessionDescriptionInterface* sdesc) {
189 auto* desc = sdesc->description();
190 RTC_DCHECK(desc->contents().size() > 0);
191 auto* transport_info =
192 desc->GetTransportInfoByName(desc->contents()[0].name);
193 RTC_DCHECK(transport_info);
194 return &transport_info->description;
195 }
196
197 const cricket::TransportDescription* GetFirstTransportDescription(
198 const SessionDescriptionInterface* sdesc) {
199 auto* desc = sdesc->description();
200 RTC_DCHECK(desc->contents().size() > 0);
201 auto* transport_info =
202 desc->GetTransportInfoByName(desc->contents()[0].name);
203 RTC_DCHECK(transport_info);
204 return &transport_info->description;
205 }
206
Qingsi Wange1692722017-11-29 13:27:20 -0800207 // TODO(qingsi): Rewrite this method in terms of the standard IceTransport
208 // after it is implemented.
209 cricket::IceRole GetIceRole(const WrapperPtr& pc_wrapper_ptr) {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100210 auto* pc_proxy =
211 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
212 pc_wrapper_ptr->pc());
213 PeerConnection* pc = static_cast<PeerConnection*>(pc_proxy->internal());
Steve Antonb8867112018-02-13 10:07:54 -0800214 for (auto transceiver : pc->GetTransceiversInternal()) {
Steve Anton69470252018-02-09 11:43:08 -0800215 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Amit Hilbuchdd9390c2018-11-13 16:26:05 -0800216 // TODO(amithi): This test seems to be using a method that should not
217 // be public |rtp_packet_transport|. Because the test is not mocking
218 // the channels or transceiver, workaround will be to |static_cast|
219 // the channel until the method is rewritten.
220 cricket::BaseChannel* channel = static_cast<cricket::BaseChannel*>(
221 transceiver->internal()->channel());
Steve Anton46d926a2018-01-23 10:23:06 -0800222 if (channel) {
Zhi Huange830e682018-03-30 10:48:35 -0700223 auto dtls_transport = static_cast<cricket::DtlsTransportInternal*>(
224 channel->rtp_packet_transport());
225 return dtls_transport->ice_transport()->GetIceRole();
Steve Anton46d926a2018-01-23 10:23:06 -0800226 }
227 }
228 }
229 RTC_NOTREACHED();
230 return cricket::ICEROLE_UNKNOWN;
Qingsi Wange1692722017-11-29 13:27:20 -0800231 }
232
Steve Antonf1c6db12017-10-13 11:13:35 -0700233 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
234 SessionDescriptionInterface* sdesc) {
235 auto* desc = sdesc->description();
236 RTC_DCHECK(desc->contents().size() > 0);
237 const auto& first_content = desc->contents()[0];
238 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -0700239 std::unique_ptr<IceCandidateInterface> jsep_candidate =
240 CreateIceCandidate(first_content.name, 0, *candidate);
241 return sdesc->AddCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700242 }
243
244 rtc::FakeNetworkManager* NewFakeNetwork() {
245 // The PeerConnection's port allocator is tied to the PeerConnection's
246 // lifetime and expects the underlying NetworkManager to outlive it. That
247 // prevents us from having the PeerConnectionWrapper own the fake network.
248 // Therefore, the test fixture will own all the fake networks even though
249 // tests should access the fake network through the PeerConnectionWrapper.
250 auto* fake_network = new rtc::FakeNetworkManager();
251 fake_networks_.emplace_back(fake_network);
252 return fake_network;
253 }
254
255 std::unique_ptr<rtc::VirtualSocketServer> vss_;
256 rtc::AutoSocketServerThread main_;
257 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
258 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton46d926a2018-01-23 10:23:06 -0800259 const SdpSemantics sdp_semantics_;
260};
261
262class PeerConnectionIceTest
263 : public PeerConnectionIceBaseTest,
264 public ::testing::WithParamInterface<SdpSemantics> {
265 protected:
Harald Alvestrand76829d72018-07-18 23:24:36 +0200266 PeerConnectionIceTest() : PeerConnectionIceBaseTest(GetParam()) {
267 webrtc::metrics::Reset();
268 }
Steve Antonf1c6db12017-10-13 11:13:35 -0700269};
270
271::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
272 const char* b_expr,
273 const cricket::Candidate& a,
274 const cricket::Candidate& b) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200275 rtc::StringBuilder failure_info;
Steve Antonf1c6db12017-10-13 11:13:35 -0700276 if (a.component() != b.component()) {
277 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
278 }
279 if (a.protocol() != b.protocol()) {
280 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
281 }
282 if (a.address() != b.address()) {
283 failure_info << "\naddress: " << a.address().ToString()
284 << " != " << b.address().ToString();
285 }
286 if (a.type() != b.type()) {
287 failure_info << "\ntype: " << a.type() << " != " << b.type();
288 }
289 std::string failure_info_str = failure_info.str();
290 if (failure_info_str.empty()) {
291 return ::testing::AssertionSuccess();
292 } else {
293 return ::testing::AssertionFailure()
294 << a_expr << " and " << b_expr << " are not equal"
295 << failure_info_str;
296 }
297}
298
Steve Anton46d926a2018-01-23 10:23:06 -0800299TEST_P(PeerConnectionIceTest, OfferContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700300 const SocketAddress kLocalAddress("1.1.1.1", 0);
301
302 auto caller = CreatePeerConnectionWithAudioVideo();
303 caller->network()->AddInterface(kLocalAddress);
304
305 // Start ICE candidate gathering by setting the local offer.
306 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
307
308 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
309
310 auto offer = caller->CreateOffer();
311 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
312 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
313 offer->candidates(0)->count());
314 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
315 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
316 offer->candidates(1)->count());
317}
318
Steve Anton46d926a2018-01-23 10:23:06 -0800319TEST_P(PeerConnectionIceTest, AnswerContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700320 const SocketAddress kCallerAddress("1.1.1.1", 0);
321
322 auto caller = CreatePeerConnectionWithAudioVideo();
323 auto callee = CreatePeerConnectionWithAudioVideo();
324 caller->network()->AddInterface(kCallerAddress);
325
326 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
327 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
328
329 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
330
Steve Antondffead82018-02-06 10:31:29 -0800331 auto* answer = callee->pc()->local_description();
Steve Antonf1c6db12017-10-13 11:13:35 -0700332 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
333 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
334 answer->candidates(0)->count());
335 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
336 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
337 answer->candidates(1)->count());
338}
339
Steve Anton46d926a2018-01-23 10:23:06 -0800340TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700341 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
342 const SocketAddress kCallerAddress("1.1.1.1", 1111);
343
344 auto caller = CreatePeerConnectionWithAudioVideo();
345 auto callee = CreatePeerConnectionWithAudioVideo();
346
347 auto offer = caller->CreateOfferAndSetAsLocal();
348 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
349 AddCandidateToFirstTransport(&candidate, offer.get());
350
351 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
352 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
353 ASSERT_EQ(1u, remote_candidates.size());
354 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
355 remote_candidates[0]->candidate());
356}
357
Steve Anton46d926a2018-01-23 10:23:06 -0800358TEST_P(PeerConnectionIceTest, SetLocalDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700359 auto caller = CreatePeerConnectionWithAudioVideo();
360
361 auto offer = caller->CreateOffer();
362 RemoveIceUfragPwd(offer.get());
363
364 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
365}
366
Steve Anton46d926a2018-01-23 10:23:06 -0800367TEST_P(PeerConnectionIceTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700368 auto caller = CreatePeerConnectionWithAudioVideo();
369 auto callee = CreatePeerConnectionWithAudioVideo();
370
371 auto offer = caller->CreateOfferAndSetAsLocal();
372 RemoveIceUfragPwd(offer.get());
373
374 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
375}
376
Steve Antonf764cf42018-05-01 14:32:17 -0700377// Test that doing an offer/answer exchange with no transport (i.e., no data
378// channel or media) results in the ICE connection state staying at New.
379TEST_P(PeerConnectionIceTest,
380 OfferAnswerWithNoTransportsDoesNotChangeIceConnectionState) {
381 auto caller = CreatePeerConnection();
382 auto callee = CreatePeerConnection();
383
384 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
385
386 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
387 caller->pc()->ice_connection_state());
388 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
389 callee->pc()->ice_connection_state());
390}
391
Steve Antonf1c6db12017-10-13 11:13:35 -0700392// The following group tests that ICE candidates are not generated before
393// SetLocalDescription is called on a PeerConnection.
394
Steve Anton46d926a2018-01-23 10:23:06 -0800395TEST_P(PeerConnectionIceTest, NoIceCandidatesBeforeSetLocalDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700396 const SocketAddress kLocalAddress("1.1.1.1", 0);
397
398 auto caller = CreatePeerConnectionWithAudioVideo();
399 caller->network()->AddInterface(kLocalAddress);
400
401 // Pump for 1 second and verify that no candidates are generated.
402 rtc::Thread::Current()->ProcessMessages(1000);
403
404 EXPECT_EQ(0u, caller->observer()->candidates_.size());
405}
Steve Anton46d926a2018-01-23 10:23:06 -0800406TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700407 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
408 const SocketAddress kCallerAddress("1.1.1.1", 1111);
409
410 auto caller = CreatePeerConnectionWithAudioVideo();
411 auto callee = CreatePeerConnectionWithAudioVideo();
412 caller->network()->AddInterface(kCallerAddress);
413
414 auto offer = caller->CreateOfferAndSetAsLocal();
415 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
416 AddCandidateToFirstTransport(&candidate, offer.get());
417 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
418
419 // Pump for 1 second and verify that no candidates are generated.
420 rtc::Thread::Current()->ProcessMessages(1000);
421
422 EXPECT_EQ(0u, callee->observer()->candidates_.size());
423}
424
Steve Anton46d926a2018-01-23 10:23:06 -0800425TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenRemoteDescriptionNotSet) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700426 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
427
428 auto caller = CreatePeerConnectionWithAudioVideo();
429 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton27ab0e52018-07-23 15:11:53 -0700430 std::unique_ptr<IceCandidateInterface> jsep_candidate =
431 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
Steve Antonf1c6db12017-10-13 11:13:35 -0700432
Steve Anton27ab0e52018-07-23 15:11:53 -0700433 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700434
435 caller->CreateOfferAndSetAsLocal();
436
Steve Anton27ab0e52018-07-23 15:11:53 -0700437 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Harald Alvestrand76829d72018-07-18 23:24:36 +0200438 EXPECT_EQ(
439 2, webrtc::metrics::NumSamples("WebRTC.PeerConnection.AddIceCandidate"));
440 EXPECT_EQ(
441 2, webrtc::metrics::NumEvents("WebRTC.PeerConnection.AddIceCandidate",
442 kAddIceCandidateFailNoRemoteDescription));
Steve Antonf1c6db12017-10-13 11:13:35 -0700443}
444
Steve Antonc79268f2018-04-24 09:54:10 -0700445TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenPeerConnectionClosed) {
446 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
447
448 auto caller = CreatePeerConnectionWithAudioVideo();
449 auto callee = CreatePeerConnectionWithAudioVideo();
450
451 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
452
453 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
454 auto* audio_content = cricket::GetFirstAudioContent(
455 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700456 std::unique_ptr<IceCandidateInterface> jsep_candidate =
457 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700458
459 caller->pc()->Close();
460
Steve Anton27ab0e52018-07-23 15:11:53 -0700461 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700462}
463
Steve Anton46d926a2018-01-23 10:23:06 -0800464TEST_P(PeerConnectionIceTest, DuplicateIceCandidateIgnoredWhenAdded) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700465 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
466
467 auto caller = CreatePeerConnectionWithAudioVideo();
468 auto callee = CreatePeerConnectionWithAudioVideo();
469
470 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
471 ASSERT_TRUE(
472 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
473
474 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
475 caller->AddIceCandidate(&candidate);
476 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
477 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
478}
479
Steve Anton46d926a2018-01-23 10:23:06 -0800480TEST_P(PeerConnectionIceTest,
Steve Antonc79268f2018-04-24 09:54:10 -0700481 CannotRemoveIceCandidatesWhenPeerConnectionClosed) {
482 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
483
484 auto caller = CreatePeerConnectionWithAudioVideo();
485 auto callee = CreatePeerConnectionWithAudioVideo();
486
487 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
488
489 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
490 auto* audio_content = cricket::GetFirstAudioContent(
491 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700492 std::unique_ptr<IceCandidateInterface> ice_candidate =
493 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700494
Steve Anton27ab0e52018-07-23 15:11:53 -0700495 ASSERT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700496
497 caller->pc()->Close();
498
499 EXPECT_FALSE(caller->pc()->RemoveIceCandidates({candidate}));
500}
501
502TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700503 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
504 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
505
506 auto caller = CreatePeerConnectionWithAudioVideo();
507 auto callee = CreatePeerConnectionWithAudioVideo();
508
509 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
510 ASSERT_TRUE(
511 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
512
513 // |candidate.transport_name()| is empty.
514 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton46d926a2018-01-23 10:23:06 -0800515 auto* audio_content = cricket::GetFirstAudioContent(
516 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700517 std::unique_ptr<IceCandidateInterface> ice_candidate =
518 CreateIceCandidate(audio_content->name, 0, candidate);
519 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700520 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
521}
522
Steve Anton46d926a2018-01-23 10:23:06 -0800523TEST_P(PeerConnectionIceTest, RemoveCandidateRemovesFromRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700524 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
525
526 auto caller = CreatePeerConnectionWithAudioVideo();
527 auto callee = CreatePeerConnectionWithAudioVideo();
528
529 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
530 ASSERT_TRUE(
531 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
532
533 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
534 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
535 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
536 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
537}
538
539// Test that if a candidate is added via AddIceCandidate and via an updated
540// remote description, then both candidates appear in the stored remote
541// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800542TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700543 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
544 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
545 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
546
547 auto caller = CreatePeerConnectionWithAudioVideo();
548 auto callee = CreatePeerConnectionWithAudioVideo();
549
550 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
551 ASSERT_TRUE(
552 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
553
554 // Add one candidate via |AddIceCandidate|.
555 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
556 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
557
558 // Add the second candidate via a reoffer.
559 auto offer = caller->CreateOffer();
560 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
561 AddCandidateToFirstTransport(&candidate2, offer.get());
562
563 // Expect both candidates to appear in the callee's remote description.
564 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
565 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
566}
567
568// The follow test verifies that SetLocal/RemoteDescription fails when an offer
569// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
570// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
571// pwd must be 22-256 characters and ufrag must be 4-256 characters.
Steve Anton46d926a2018-01-23 10:23:06 -0800572TEST_P(PeerConnectionIceTest, VerifyUfragPwdLength) {
Yves Gerey665174f2018-06-19 15:03:05 +0200573 auto set_local_description_with_ufrag_pwd_length = [this](int ufrag_len,
574 int pwd_len) {
575 auto pc = CreatePeerConnectionWithAudioVideo();
576 auto offer = pc->CreateOffer();
577 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
578 std::string(pwd_len, 'x'));
579 return pc->SetLocalDescription(std::move(offer));
580 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700581
Yves Gerey665174f2018-06-19 15:03:05 +0200582 auto set_remote_description_with_ufrag_pwd_length = [this](int ufrag_len,
583 int pwd_len) {
584 auto pc = CreatePeerConnectionWithAudioVideo();
585 auto offer = pc->CreateOffer();
586 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
587 std::string(pwd_len, 'x'));
588 return pc->SetRemoteDescription(std::move(offer));
589 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700590
591 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
592 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
593 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
594 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
595 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
596 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
597 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
598 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
599 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
600 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
601 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
602 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
603}
604
605::testing::AssertionResult AssertIpInCandidates(
606 const char* address_expr,
607 const char* candidates_expr,
608 const SocketAddress& address,
609 const std::vector<IceCandidateInterface*> candidates) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200610 rtc::StringBuilder candidate_hosts;
Steve Antonf1c6db12017-10-13 11:13:35 -0700611 for (const auto* candidate : candidates) {
612 const auto& candidate_ip = candidate->candidate().address().ipaddr();
613 if (candidate_ip == address.ipaddr()) {
614 return ::testing::AssertionSuccess();
615 }
Jonas Olssonabbe8412018-04-03 13:40:05 +0200616 candidate_hosts << "\n" << candidate_ip.ToString();
Steve Antonf1c6db12017-10-13 11:13:35 -0700617 }
618 return ::testing::AssertionFailure()
619 << address_expr << " (host " << address.HostAsURIString()
620 << ") not in " << candidates_expr
621 << " which have the following address hosts:" << candidate_hosts.str();
622}
623
Steve Anton46d926a2018-01-23 10:23:06 -0800624TEST_P(PeerConnectionIceTest, CandidatesGeneratedForEachLocalInterface) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700625 const SocketAddress kLocalAddress1("1.1.1.1", 0);
626 const SocketAddress kLocalAddress2("2.2.2.2", 0);
627
628 auto caller = CreatePeerConnectionWithAudioVideo();
629 caller->network()->AddInterface(kLocalAddress1);
630 caller->network()->AddInterface(kLocalAddress2);
631
632 caller->CreateOfferAndSetAsLocal();
633 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
634
635 auto candidates = caller->observer()->GetCandidatesByMline(0);
636 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
637 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
638}
639
Steve Anton46d926a2018-01-23 10:23:06 -0800640TEST_P(PeerConnectionIceTest, TrickledSingleCandidateAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700641 const SocketAddress kCallerAddress("1.1.1.1", 1111);
642
643 auto caller = CreatePeerConnectionWithAudioVideo();
644 auto callee = CreatePeerConnectionWithAudioVideo();
645
646 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
647
648 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
649 callee->AddIceCandidate(&candidate);
650 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
651 ASSERT_EQ(1u, candidates.size());
652 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
653 candidates[0]->candidate());
654}
655
Steve Anton46d926a2018-01-23 10:23:06 -0800656TEST_P(PeerConnectionIceTest, TwoTrickledCandidatesAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700657 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
658 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
659
660 auto caller = CreatePeerConnectionWithAudioVideo();
661 auto callee = CreatePeerConnectionWithAudioVideo();
662
663 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
664 ASSERT_TRUE(
665 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
666
667 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
668 caller->AddIceCandidate(&candidate1);
669
670 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
671 caller->AddIceCandidate(&candidate2);
672
673 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
674 ASSERT_EQ(2u, candidates.size());
675 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
676 candidates[0]->candidate());
677 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
678 candidates[1]->candidate());
679}
680
Steve Anton46d926a2018-01-23 10:23:06 -0800681TEST_P(PeerConnectionIceTest, LocalDescriptionUpdatedWhenContinualGathering) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700682 const SocketAddress kLocalAddress("1.1.1.1", 0);
683
684 RTCConfiguration config;
685 config.continual_gathering_policy =
686 PeerConnectionInterface::GATHER_CONTINUALLY;
687 auto caller = CreatePeerConnectionWithAudioVideo(config);
688 caller->network()->AddInterface(kLocalAddress);
689
690 // Start ICE candidate gathering by setting the local offer.
691 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
692
693 // Since we're using continual gathering, we won't get "gathering done".
694 EXPECT_TRUE_WAIT(
695 caller->pc()->local_description()->candidates(0)->count() > 0,
696 kIceCandidatesTimeout);
697}
698
699// Test that when continual gathering is enabled, and a network interface goes
700// down, the candidate is signaled as removed and removed from the local
701// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800702TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700703 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
704 const SocketAddress kLocalAddress("1.1.1.1", 0);
705
706 RTCConfiguration config;
707 config.continual_gathering_policy =
708 PeerConnectionInterface::GATHER_CONTINUALLY;
709 auto caller = CreatePeerConnectionWithAudioVideo(config);
710 caller->network()->AddInterface(kLocalAddress);
711
712 // Start ICE candidate gathering by setting the local offer.
713 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
714
715 EXPECT_TRUE_WAIT(
716 caller->pc()->local_description()->candidates(0)->count() > 0,
717 kIceCandidatesTimeout);
718
719 // Remove the only network interface, causing the PeerConnection to signal
720 // the removal of all candidates derived from this interface.
721 caller->network()->RemoveInterface(kLocalAddress);
722
723 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
724 kIceCandidatesTimeout);
725 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
726}
727
Steve Anton46d926a2018-01-23 10:23:06 -0800728TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700729 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
730 const SocketAddress kLocalAddress("1.1.1.1", 0);
731
732 RTCConfiguration config;
733 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
734 auto caller = CreatePeerConnectionWithAudioVideo(config);
735 caller->network()->AddInterface(kLocalAddress);
736
737 // Start ICE candidate gathering by setting the local offer.
738 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
739
740 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
741
742 caller->network()->RemoveInterface(kLocalAddress);
743
744 // Verify that the local candidates are not removed;
745 rtc::Thread::Current()->ProcessMessages(1000);
746 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
747}
748
749// The following group tests that when an offer includes a new ufrag or pwd
750// (indicating an ICE restart) the old candidates are removed and new candidates
751// added to the remote description.
752
Steve Anton46d926a2018-01-23 10:23:06 -0800753TEST_P(PeerConnectionIceTest, IceRestartOfferClearsExistingCandidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700754 const SocketAddress kCallerAddress("1.1.1.1", 1111);
755
756 auto caller = CreatePeerConnectionWithAudioVideo();
757 auto callee = CreatePeerConnectionWithAudioVideo();
758
759 auto offer = caller->CreateOffer();
760 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
761 AddCandidateToFirstTransport(&candidate, offer.get());
762
763 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
764
765 RTCOfferAnswerOptions options;
766 options.ice_restart = true;
767 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOffer(options)));
768
769 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
770}
Steve Anton46d926a2018-01-23 10:23:06 -0800771TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700772 IceRestartOfferCandidateReplacesExistingCandidate) {
773 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
774 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
775
776 auto caller = CreatePeerConnectionWithAudioVideo();
777 auto callee = CreatePeerConnectionWithAudioVideo();
778
779 auto offer = caller->CreateOffer();
780 cricket::Candidate old_candidate =
781 CreateLocalUdpCandidate(kFirstCallerAddress);
782 AddCandidateToFirstTransport(&old_candidate, offer.get());
783
784 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
785
786 RTCOfferAnswerOptions options;
787 options.ice_restart = true;
788 auto restart_offer = caller->CreateOffer(options);
789 cricket::Candidate new_candidate =
790 CreateLocalUdpCandidate(kRestartedCallerAddress);
791 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
792
793 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
794
795 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
796 ASSERT_EQ(1u, remote_candidates.size());
797 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
798 remote_candidates[0]->candidate());
799}
800
801// Test that if there is not an ICE restart (i.e., nothing changes), then the
802// answer to a later offer should have the same ufrag/pwd as the first answer.
Steve Anton46d926a2018-01-23 10:23:06 -0800803TEST_P(PeerConnectionIceTest, LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700804 auto caller = CreatePeerConnectionWithAudioVideo();
805 auto callee = CreatePeerConnectionWithAudioVideo();
806
807 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
808 ASSERT_TRUE(
809 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
810
811 // Re-offer.
812 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
813
814 auto answer = callee->CreateAnswer();
815 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
816 auto* local_transport_desc =
817 GetFirstTransportDescription(callee->pc()->local_description());
818
819 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
820 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
821}
822
823// The following parameterized test verifies that if an offer is sent with a
824// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
825// other side has initiated an ICE restart and generate a new ufrag and pwd.
826// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
827// a=ice-pwd attributes compared to the previous SDP from the peer, it
828// indicates that ICE is restarting for this media stream."
829
Steve Anton46d926a2018-01-23 10:23:06 -0800830class PeerConnectionIceUfragPwdAnswerTest
831 : public PeerConnectionIceBaseTest,
832 public ::testing::WithParamInterface<
833 std::tuple<SdpSemantics, std::tuple<bool, bool>>> {
Steve Antonf1c6db12017-10-13 11:13:35 -0700834 protected:
Steve Anton46d926a2018-01-23 10:23:06 -0800835 PeerConnectionIceUfragPwdAnswerTest()
836 : PeerConnectionIceBaseTest(std::get<0>(GetParam())) {
837 auto param = std::get<1>(GetParam());
838 offer_new_ufrag_ = std::get<0>(param);
839 offer_new_pwd_ = std::get<1>(param);
Steve Antonf1c6db12017-10-13 11:13:35 -0700840 }
841
842 bool offer_new_ufrag_;
843 bool offer_new_pwd_;
844};
845
Steve Anton46d926a2018-01-23 10:23:06 -0800846TEST_P(PeerConnectionIceUfragPwdAnswerTest, TestIncludedInAnswer) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700847 auto caller = CreatePeerConnectionWithAudioVideo();
848 auto callee = CreatePeerConnectionWithAudioVideo();
849
850 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
851 ASSERT_TRUE(
852 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
853
854 auto offer = caller->CreateOffer();
855 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
856 if (offer_new_ufrag_) {
857 offer_transport_desc->ice_ufrag += "_new";
858 }
859 if (offer_new_pwd_) {
860 offer_transport_desc->ice_pwd += "_new";
861 }
862
863 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
864
865 auto answer = callee->CreateAnswer();
866 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
867 auto* local_transport_desc =
868 GetFirstTransportDescription(callee->pc()->local_description());
869
870 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
871 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
872}
873
874INSTANTIATE_TEST_CASE_P(
Steve Anton46d926a2018-01-23 10:23:06 -0800875 PeerConnectionIceTest,
876 PeerConnectionIceUfragPwdAnswerTest,
877 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
878 Values(std::make_pair(true, true), // Both changed.
879 std::make_pair(true, false), // Only ufrag changed.
880 std::make_pair(false, true)))); // Only pwd changed.
Steve Antonf1c6db12017-10-13 11:13:35 -0700881
882// Test that if an ICE restart is offered on one media section, then the answer
883// will only change ICE ufrag/pwd for that section and keep the other sections
884// the same.
885// Note that this only works if we have disabled BUNDLE, otherwise all media
886// sections will share the same transport.
Steve Anton46d926a2018-01-23 10:23:06 -0800887TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700888 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
889 auto caller = CreatePeerConnectionWithAudioVideo();
890 auto callee = CreatePeerConnectionWithAudioVideo();
891
892 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
893 ASSERT_TRUE(
894 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
895
896 RTCOfferAnswerOptions disable_bundle_options;
897 disable_bundle_options.use_rtp_mux = false;
898
899 auto offer = caller->CreateOffer(disable_bundle_options);
900
901 // Signal ICE restart on the first media section.
902 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
903 offer_transport_desc->ice_ufrag += "_new";
904 offer_transport_desc->ice_pwd += "_new";
905
906 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
907
908 auto answer = callee->CreateAnswer(disable_bundle_options);
909 const auto& answer_transports = answer->description()->transport_infos();
910 const auto& local_transports =
911 callee->pc()->local_description()->description()->transport_infos();
912
913 EXPECT_NE(answer_transports[0].description.ice_ufrag,
914 local_transports[0].description.ice_ufrag);
915 EXPECT_NE(answer_transports[0].description.ice_pwd,
916 local_transports[0].description.ice_pwd);
917 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
918 local_transports[1].description.ice_ufrag);
919 EXPECT_EQ(answer_transports[1].description.ice_pwd,
920 local_transports[1].description.ice_pwd);
921}
922
Qingsi Wange1692722017-11-29 13:27:20 -0800923// Test that when the initial offerer (caller) uses the lite implementation of
924// ICE and the callee uses the full implementation, the caller takes the
925// CONTROLLED role and the callee takes the CONTROLLING role. This is specified
926// in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -0800927TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -0800928 OfferFromLiteIceControlledAndAnswerFromFullIceControlling) {
929 auto caller = CreatePeerConnectionWithAudioVideo();
930 auto callee = CreatePeerConnectionWithAudioVideo();
931
932 auto offer = caller->CreateOffer();
933 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
934 ASSERT_TRUE(
935 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
936 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
937
938 auto answer = callee->CreateAnswer();
939 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_FULL);
940 ASSERT_TRUE(
941 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
942 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
943
944 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(caller));
945 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(callee));
946}
947
948// Test that when the caller and the callee both use the lite implementation of
949// ICE, the initial offerer (caller) takes the CONTROLLING role and the callee
950// takes the CONTROLLED role. This is specified in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -0800951TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -0800952 OfferFromLiteIceControllingAndAnswerFromLiteIceControlled) {
953 auto caller = CreatePeerConnectionWithAudioVideo();
954 auto callee = CreatePeerConnectionWithAudioVideo();
955
956 auto offer = caller->CreateOffer();
957 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
958 ASSERT_TRUE(
959 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
960 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
961
962 auto answer = callee->CreateAnswer();
963 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_LITE);
964 ASSERT_TRUE(
965 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
966 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
967
968 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(caller));
969 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(callee));
970}
971
Steve Anton46d926a2018-01-23 10:23:06 -0800972INSTANTIATE_TEST_CASE_P(PeerConnectionIceTest,
973 PeerConnectionIceTest,
974 Values(SdpSemantics::kPlanB,
975 SdpSemantics::kUnifiedPlan));
976
Qingsi Wang4ff54432018-03-01 18:25:20 -0800977class PeerConnectionIceConfigTest : public testing::Test {
978 protected:
979 void SetUp() override {
980 pc_factory_ = CreatePeerConnectionFactory(
981 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
982 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
Anders Carlsson67537952018-05-03 11:28:29 +0200983 CreateBuiltinAudioDecoderFactory(), CreateBuiltinVideoEncoderFactory(),
984 CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
985 nullptr /* audio_processing */);
Qingsi Wang4ff54432018-03-01 18:25:20 -0800986 }
987 void CreatePeerConnection(const RTCConfiguration& config) {
988 std::unique_ptr<cricket::FakePortAllocator> port_allocator(
989 new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr));
990 port_allocator_ = port_allocator.get();
991 rtc::scoped_refptr<PeerConnectionInterface> pc(
Niels Möllerf06f9232018-08-07 12:32:18 +0200992 pc_factory_->CreatePeerConnection(config, std::move(port_allocator),
993 nullptr /* cert_generator */,
994 &observer_));
Qingsi Wang4ff54432018-03-01 18:25:20 -0800995 EXPECT_TRUE(pc.get());
996 pc_ = std::move(pc.get());
997 }
998
999 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_ = nullptr;
1000 rtc::scoped_refptr<PeerConnectionInterface> pc_ = nullptr;
1001 cricket::FakePortAllocator* port_allocator_ = nullptr;
1002
1003 MockPeerConnectionObserver observer_;
1004};
1005
1006TEST_F(PeerConnectionIceConfigTest, SetStunCandidateKeepaliveInterval) {
1007 RTCConfiguration config;
1008 config.stun_candidate_keepalive_interval = 123;
1009 config.ice_candidate_pool_size = 1;
1010 CreatePeerConnection(config);
1011 ASSERT_NE(port_allocator_, nullptr);
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001012 absl::optional<int> actual_stun_keepalive_interval =
Qingsi Wang4ff54432018-03-01 18:25:20 -08001013 port_allocator_->stun_candidate_keepalive_interval();
1014 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 123);
1015 config.stun_candidate_keepalive_interval = 321;
1016 RTCError error;
1017 pc_->SetConfiguration(config, &error);
1018 actual_stun_keepalive_interval =
1019 port_allocator_->stun_candidate_keepalive_interval();
1020 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 321);
1021}
1022
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001023TEST_P(PeerConnectionIceTest, IceCredentialsCreateOffer) {
1024 RTCConfiguration config;
1025 config.ice_candidate_pool_size = 1;
1026 auto pc = CreatePeerConnectionWithAudioVideo(config);
1027 ASSERT_NE(pc->port_allocator_, nullptr);
1028 auto offer = pc->CreateOffer();
1029 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1030 ASSERT_EQ(1u, credentials.size());
1031
1032 auto* desc = offer->description();
1033 for (const auto& content : desc->contents()) {
1034 auto* transport_info = desc->GetTransportInfoByName(content.name);
1035 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1036 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1037 }
1038}
1039
1040TEST_P(PeerConnectionIceTest, IceCredentialsCreateAnswer) {
1041 RTCConfiguration config;
1042 config.ice_candidate_pool_size = 1;
1043 auto pc = CreatePeerConnectionWithAudioVideo(config);
1044 ASSERT_NE(pc->port_allocator_, nullptr);
1045 auto offer = pc->CreateOffer();
1046 ASSERT_TRUE(pc->SetRemoteDescription(std::move(offer)));
1047 auto answer = pc->CreateAnswer();
1048
1049 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1050 ASSERT_EQ(1u, credentials.size());
1051
1052 auto* desc = answer->description();
1053 for (const auto& content : desc->contents()) {
1054 auto* transport_info = desc->GetTransportInfoByName(content.name);
1055 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1056 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1057 }
1058}
1059
Steve Antonf1c6db12017-10-13 11:13:35 -07001060} // namespace webrtc