blob: 49a79a2556b4f5a1d05189f545de2425280c841c [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
Mirko Bonadei317a1f02019-09-17 17:06:18 +020011#include <memory>
12
Steve Anton10542f22019-01-11 09:11:00 -080013#include "p2p/base/fake_port_allocator.h"
14#include "p2p/base/test_stun_server.h"
15#include "p2p/client/basic_port_allocator.h"
16#include "pc/media_session.h"
17#include "pc/peer_connection.h"
18#include "pc/peer_connection_wrapper.h"
19#include "pc/sdp_utils.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070020#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080021#include "pc/test/android_test_initializer.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070022#endif
Karl Wiberg1b0eae32017-10-17 14:48:54 +020023#include "api/audio_codecs/builtin_audio_decoder_factory.h"
24#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Mirko Bonadei2ff3f492018-11-22 09:00:13 +010025#include "api/create_peerconnection_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "api/uma_metrics.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"
Markus Handella1b82012021-05-26 18:56:30 +020029#include "pc/peer_connection_proxy.h"
Steve Anton10542f22019-01-11 09:11:00 -080030#include "pc/test/fake_audio_capture_module.h"
Henrik Boströmee6f4f62019-11-06 12:36:12 +010031#include "pc/test/mock_peer_connection_observers.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "rtc_base/fake_network.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070033#include "rtc_base/gunit.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020034#include "rtc_base/strings/string_builder.h"
Steve Anton10542f22019-01-11 09:11:00 -080035#include "rtc_base/virtual_socket_server.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020036#include "system_wrappers/include/metrics.h"
Steve Antonb443dfe2019-03-05 14:09:49 -080037#include "test/gmock.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070038
39namespace webrtc {
40
41using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
42using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
43using rtc::SocketAddress;
Steve Anton46d926a2018-01-23 10:23:06 -080044using ::testing::Combine;
Steve Antonb443dfe2019-03-05 14:09:49 -080045using ::testing::ElementsAre;
46using ::testing::Pair;
Steve Antonf1c6db12017-10-13 11:13:35 -070047using ::testing::Values;
48
49constexpr int kIceCandidatesTimeout = 10000;
Henrik Boströmee6f4f62019-11-06 12:36:12 +010050constexpr int64_t kWaitTimeout = 10000;
Steve Antonf1c6db12017-10-13 11:13:35 -070051
Steve Anton46d926a2018-01-23 10:23:06 -080052class PeerConnectionWrapperForIceTest : public PeerConnectionWrapper {
Steve Antonf1c6db12017-10-13 11:13:35 -070053 public:
54 using PeerConnectionWrapper::PeerConnectionWrapper;
55
Henrik Boströmee6f4f62019-11-06 12:36:12 +010056 std::unique_ptr<IceCandidateInterface> CreateJsepCandidateForFirstTransport(
57 cricket::Candidate* candidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -070058 RTC_DCHECK(pc()->remote_description());
59 const auto* desc = pc()->remote_description()->description();
60 RTC_DCHECK(desc->contents().size() > 0);
61 const auto& first_content = desc->contents()[0];
62 candidate->set_transport_name(first_content.name);
Henrik Boströmee6f4f62019-11-06 12:36:12 +010063 return CreateIceCandidate(first_content.name, -1, *candidate);
64 }
65
66 // Adds a new ICE candidate to the first transport.
67 bool AddIceCandidate(cricket::Candidate* candidate) {
68 return pc()->AddIceCandidate(
69 CreateJsepCandidateForFirstTransport(candidate).get());
Steve Antonf1c6db12017-10-13 11:13:35 -070070 }
71
72 // Returns ICE candidates from the remote session description.
73 std::vector<const IceCandidateInterface*>
74 GetIceCandidatesFromRemoteDescription() {
75 const SessionDescriptionInterface* sdesc = pc()->remote_description();
76 RTC_DCHECK(sdesc);
77 std::vector<const IceCandidateInterface*> candidates;
78 for (size_t mline_index = 0; mline_index < sdesc->number_of_mediasections();
79 mline_index++) {
80 const auto* candidate_collection = sdesc->candidates(mline_index);
81 for (size_t i = 0; i < candidate_collection->count(); i++) {
82 candidates.push_back(candidate_collection->at(i));
83 }
84 }
85 return candidates;
86 }
87
88 rtc::FakeNetworkManager* network() { return network_; }
89
90 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
91
Jonas Oreland1cd39fa2018-10-11 07:47:12 +020092 // The port allocator used by this PC.
93 cricket::PortAllocator* port_allocator_;
94
Steve Antonf1c6db12017-10-13 11:13:35 -070095 private:
96 rtc::FakeNetworkManager* network_;
97};
98
Steve Anton46d926a2018-01-23 10:23:06 -080099class PeerConnectionIceBaseTest : public ::testing::Test {
Steve Antonf1c6db12017-10-13 11:13:35 -0700100 protected:
Steve Anton46d926a2018-01-23 10:23:06 -0800101 typedef std::unique_ptr<PeerConnectionWrapperForIceTest> WrapperPtr;
Steve Antonf1c6db12017-10-13 11:13:35 -0700102
Steve Anton46d926a2018-01-23 10:23:06 -0800103 explicit PeerConnectionIceBaseTest(SdpSemantics sdp_semantics)
104 : vss_(new rtc::VirtualSocketServer()),
105 main_(vss_.get()),
106 sdp_semantics_(sdp_semantics) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700107#ifdef WEBRTC_ANDROID
108 InitializeAndroidObjects();
109#endif
110 pc_factory_ = CreatePeerConnectionFactory(
111 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Anders Carlsson67537952018-05-03 11:28:29 +0200112 rtc::scoped_refptr<AudioDeviceModule>(FakeAudioCaptureModule::Create()),
113 CreateBuiltinAudioEncoderFactory(), CreateBuiltinAudioDecoderFactory(),
114 CreateBuiltinVideoEncoderFactory(), CreateBuiltinVideoDecoderFactory(),
115 nullptr /* audio_mixer */, nullptr /* audio_processing */);
Steve Antonf1c6db12017-10-13 11:13:35 -0700116 }
117
118 WrapperPtr CreatePeerConnection() {
119 return CreatePeerConnection(RTCConfiguration());
120 }
121
122 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
123 auto* fake_network = NewFakeNetwork();
124 auto port_allocator =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200125 std::make_unique<cricket::BasicPortAllocator>(fake_network);
Steve Antonf1c6db12017-10-13 11:13:35 -0700126 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
127 cricket::PORTALLOCATOR_DISABLE_RELAY);
128 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
Steve Anton46d926a2018-01-23 10:23:06 -0800129 RTCConfiguration modified_config = config;
130 modified_config.sdp_semantics = sdp_semantics_;
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200131 auto observer = std::make_unique<MockPeerConnectionObserver>();
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200132 auto port_allocator_copy = port_allocator.get();
Steve Antonf1c6db12017-10-13 11:13:35 -0700133 auto pc = pc_factory_->CreatePeerConnection(
Steve Anton46d926a2018-01-23 10:23:06 -0800134 modified_config, std::move(port_allocator), nullptr, observer.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700135 if (!pc) {
136 return nullptr;
137 }
138
Yves Gerey4e933292018-10-31 15:36:05 +0100139 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200140 auto wrapper = std::make_unique<PeerConnectionWrapperForIceTest>(
Steve Antonf1c6db12017-10-13 11:13:35 -0700141 pc_factory_, pc, std::move(observer));
142 wrapper->set_network(fake_network);
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200143 wrapper->port_allocator_ = port_allocator_copy;
Steve Antonf1c6db12017-10-13 11:13:35 -0700144 return wrapper;
145 }
146
147 // Accepts the same arguments as CreatePeerConnection and adds default audio
148 // and video tracks.
149 template <typename... Args>
150 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
151 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
152 if (!wrapper) {
153 return nullptr;
154 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700155 wrapper->AddAudioTrack("a");
156 wrapper->AddVideoTrack("v");
Steve Antonf1c6db12017-10-13 11:13:35 -0700157 return wrapper;
158 }
159
160 cricket::Candidate CreateLocalUdpCandidate(
161 const rtc::SocketAddress& address) {
162 cricket::Candidate candidate;
163 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
164 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
165 candidate.set_address(address);
166 candidate.set_type(cricket::LOCAL_PORT_TYPE);
167 return candidate;
168 }
169
170 // Remove all ICE ufrag/pwd lines from the given session description.
171 void RemoveIceUfragPwd(SessionDescriptionInterface* sdesc) {
172 SetIceUfragPwd(sdesc, "", "");
173 }
174
175 // Sets all ICE ufrag/pwds on the given session description.
176 void SetIceUfragPwd(SessionDescriptionInterface* sdesc,
177 const std::string& ufrag,
178 const std::string& pwd) {
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_ufrag = ufrag;
183 transport_info->description.ice_pwd = pwd;
184 }
185 }
186
Qingsi Wange1692722017-11-29 13:27:20 -0800187 // Set ICE mode on the given session description.
188 void SetIceMode(SessionDescriptionInterface* sdesc,
189 const cricket::IceMode ice_mode) {
190 auto* desc = sdesc->description();
191 for (const auto& content : desc->contents()) {
192 auto* transport_info = desc->GetTransportInfoByName(content.name);
193 transport_info->description.ice_mode = ice_mode;
194 }
195 }
196
Steve Antonf1c6db12017-10-13 11:13:35 -0700197 cricket::TransportDescription* GetFirstTransportDescription(
198 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
207 const cricket::TransportDescription* GetFirstTransportDescription(
208 const SessionDescriptionInterface* sdesc) {
209 auto* desc = sdesc->description();
210 RTC_DCHECK(desc->contents().size() > 0);
211 auto* transport_info =
212 desc->GetTransportInfoByName(desc->contents()[0].name);
213 RTC_DCHECK(transport_info);
214 return &transport_info->description;
215 }
216
Qingsi Wange1692722017-11-29 13:27:20 -0800217 // TODO(qingsi): Rewrite this method in terms of the standard IceTransport
218 // after it is implemented.
219 cricket::IceRole GetIceRole(const WrapperPtr& pc_wrapper_ptr) {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100220 auto* pc_proxy =
221 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
222 pc_wrapper_ptr->pc());
223 PeerConnection* pc = static_cast<PeerConnection*>(pc_proxy->internal());
Mirko Bonadei739baf02019-01-27 17:29:42 +0100224 for (const auto& transceiver : pc->GetTransceiversInternal()) {
Steve Anton69470252018-02-09 11:43:08 -0800225 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700226 auto dtls_transport = pc->LookupDtlsTransportByMidInternal(
227 transceiver->internal()->channel()->content_name());
228 return dtls_transport->ice_transport()->internal()->GetIceRole();
Steve Anton46d926a2018-01-23 10:23:06 -0800229 }
230 }
Artem Titovd3251962021-11-15 16:57:07 +0100231 RTC_DCHECK_NOTREACHED();
Steve Anton46d926a2018-01-23 10:23:06 -0800232 return cricket::ICEROLE_UNKNOWN;
Qingsi Wange1692722017-11-29 13:27:20 -0800233 }
234
Henrik Boström79b69802019-07-18 11:16:56 +0200235 // Returns a list of (ufrag, pwd) pairs in the order that they appear in
Artem Titov880fa812021-07-30 22:30:23 +0200236 // `description`, or the empty list if `description` is null.
Henrik Boström79b69802019-07-18 11:16:56 +0200237 std::vector<std::pair<std::string, std::string>> GetIceCredentials(
238 const SessionDescriptionInterface* description) {
239 std::vector<std::pair<std::string, std::string>> ice_credentials;
240 if (!description)
241 return ice_credentials;
242 const auto* desc = description->description();
243 for (const auto& content_info : desc->contents()) {
244 const auto* transport_info =
245 desc->GetTransportInfoByName(content_info.name);
246 if (transport_info) {
247 ice_credentials.push_back(
248 std::make_pair(transport_info->description.ice_ufrag,
249 transport_info->description.ice_pwd));
250 }
251 }
252 return ice_credentials;
253 }
254
Steve Antonf1c6db12017-10-13 11:13:35 -0700255 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
256 SessionDescriptionInterface* sdesc) {
257 auto* desc = sdesc->description();
258 RTC_DCHECK(desc->contents().size() > 0);
259 const auto& first_content = desc->contents()[0];
260 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -0700261 std::unique_ptr<IceCandidateInterface> jsep_candidate =
262 CreateIceCandidate(first_content.name, 0, *candidate);
263 return sdesc->AddCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700264 }
265
266 rtc::FakeNetworkManager* NewFakeNetwork() {
267 // The PeerConnection's port allocator is tied to the PeerConnection's
268 // lifetime and expects the underlying NetworkManager to outlive it. That
269 // prevents us from having the PeerConnectionWrapper own the fake network.
270 // Therefore, the test fixture will own all the fake networks even though
271 // tests should access the fake network through the PeerConnectionWrapper.
272 auto* fake_network = new rtc::FakeNetworkManager();
273 fake_networks_.emplace_back(fake_network);
274 return fake_network;
275 }
276
277 std::unique_ptr<rtc::VirtualSocketServer> vss_;
278 rtc::AutoSocketServerThread main_;
279 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
280 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton46d926a2018-01-23 10:23:06 -0800281 const SdpSemantics sdp_semantics_;
282};
283
284class PeerConnectionIceTest
285 : public PeerConnectionIceBaseTest,
286 public ::testing::WithParamInterface<SdpSemantics> {
287 protected:
Harald Alvestrand76829d72018-07-18 23:24:36 +0200288 PeerConnectionIceTest() : PeerConnectionIceBaseTest(GetParam()) {
289 webrtc::metrics::Reset();
290 }
Steve Antonf1c6db12017-10-13 11:13:35 -0700291};
292
293::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
294 const char* b_expr,
295 const cricket::Candidate& a,
296 const cricket::Candidate& b) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200297 rtc::StringBuilder failure_info;
Steve Antonf1c6db12017-10-13 11:13:35 -0700298 if (a.component() != b.component()) {
299 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
300 }
301 if (a.protocol() != b.protocol()) {
302 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
303 }
304 if (a.address() != b.address()) {
305 failure_info << "\naddress: " << a.address().ToString()
306 << " != " << b.address().ToString();
307 }
308 if (a.type() != b.type()) {
309 failure_info << "\ntype: " << a.type() << " != " << b.type();
310 }
311 std::string failure_info_str = failure_info.str();
312 if (failure_info_str.empty()) {
313 return ::testing::AssertionSuccess();
314 } else {
315 return ::testing::AssertionFailure()
316 << a_expr << " and " << b_expr << " are not equal"
317 << failure_info_str;
318 }
319}
320
Steve Anton46d926a2018-01-23 10:23:06 -0800321TEST_P(PeerConnectionIceTest, OfferContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700322 const SocketAddress kLocalAddress("1.1.1.1", 0);
323
324 auto caller = CreatePeerConnectionWithAudioVideo();
325 caller->network()->AddInterface(kLocalAddress);
326
327 // Start ICE candidate gathering by setting the local offer.
328 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
329
330 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
331
332 auto offer = caller->CreateOffer();
333 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
334 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
335 offer->candidates(0)->count());
336 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
337 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
338 offer->candidates(1)->count());
339}
340
Steve Anton46d926a2018-01-23 10:23:06 -0800341TEST_P(PeerConnectionIceTest, AnswerContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700342 const SocketAddress kCallerAddress("1.1.1.1", 0);
343
344 auto caller = CreatePeerConnectionWithAudioVideo();
345 auto callee = CreatePeerConnectionWithAudioVideo();
346 caller->network()->AddInterface(kCallerAddress);
347
348 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
349 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
350
351 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
352
Steve Antondffead82018-02-06 10:31:29 -0800353 auto* answer = callee->pc()->local_description();
Steve Antonf1c6db12017-10-13 11:13:35 -0700354 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
355 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
356 answer->candidates(0)->count());
357 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
358 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
359 answer->candidates(1)->count());
360}
361
Steve Anton46d926a2018-01-23 10:23:06 -0800362TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700363 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
364 const SocketAddress kCallerAddress("1.1.1.1", 1111);
365
366 auto caller = CreatePeerConnectionWithAudioVideo();
367 auto callee = CreatePeerConnectionWithAudioVideo();
368
369 auto offer = caller->CreateOfferAndSetAsLocal();
370 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
371 AddCandidateToFirstTransport(&candidate, offer.get());
372
373 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
374 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
375 ASSERT_EQ(1u, remote_candidates.size());
376 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
377 remote_candidates[0]->candidate());
378}
379
Steve Anton46d926a2018-01-23 10:23:06 -0800380TEST_P(PeerConnectionIceTest, SetLocalDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700381 auto caller = CreatePeerConnectionWithAudioVideo();
382
383 auto offer = caller->CreateOffer();
384 RemoveIceUfragPwd(offer.get());
385
386 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
387}
388
Steve Anton46d926a2018-01-23 10:23:06 -0800389TEST_P(PeerConnectionIceTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700390 auto caller = CreatePeerConnectionWithAudioVideo();
391 auto callee = CreatePeerConnectionWithAudioVideo();
392
393 auto offer = caller->CreateOfferAndSetAsLocal();
394 RemoveIceUfragPwd(offer.get());
395
396 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
397}
398
Steve Antonf764cf42018-05-01 14:32:17 -0700399// Test that doing an offer/answer exchange with no transport (i.e., no data
400// channel or media) results in the ICE connection state staying at New.
401TEST_P(PeerConnectionIceTest,
402 OfferAnswerWithNoTransportsDoesNotChangeIceConnectionState) {
403 auto caller = CreatePeerConnection();
404 auto callee = CreatePeerConnection();
405
406 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
407
408 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
409 caller->pc()->ice_connection_state());
410 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
411 callee->pc()->ice_connection_state());
412}
413
Steve Antonf1c6db12017-10-13 11:13:35 -0700414// The following group tests that ICE candidates are not generated before
415// SetLocalDescription is called on a PeerConnection.
416
Steve Anton46d926a2018-01-23 10:23:06 -0800417TEST_P(PeerConnectionIceTest, NoIceCandidatesBeforeSetLocalDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700418 const SocketAddress kLocalAddress("1.1.1.1", 0);
419
420 auto caller = CreatePeerConnectionWithAudioVideo();
421 caller->network()->AddInterface(kLocalAddress);
422
423 // Pump for 1 second and verify that no candidates are generated.
424 rtc::Thread::Current()->ProcessMessages(1000);
425
426 EXPECT_EQ(0u, caller->observer()->candidates_.size());
427}
Steve Anton46d926a2018-01-23 10:23:06 -0800428TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700429 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
430 const SocketAddress kCallerAddress("1.1.1.1", 1111);
431
432 auto caller = CreatePeerConnectionWithAudioVideo();
433 auto callee = CreatePeerConnectionWithAudioVideo();
434 caller->network()->AddInterface(kCallerAddress);
435
436 auto offer = caller->CreateOfferAndSetAsLocal();
437 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
438 AddCandidateToFirstTransport(&candidate, offer.get());
439 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
440
441 // Pump for 1 second and verify that no candidates are generated.
442 rtc::Thread::Current()->ProcessMessages(1000);
443
444 EXPECT_EQ(0u, callee->observer()->candidates_.size());
445}
446
Steve Anton46d926a2018-01-23 10:23:06 -0800447TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenRemoteDescriptionNotSet) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700448 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
449
450 auto caller = CreatePeerConnectionWithAudioVideo();
451 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton27ab0e52018-07-23 15:11:53 -0700452 std::unique_ptr<IceCandidateInterface> jsep_candidate =
453 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
Steve Antonf1c6db12017-10-13 11:13:35 -0700454
Steve Anton27ab0e52018-07-23 15:11:53 -0700455 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700456
457 caller->CreateOfferAndSetAsLocal();
458
Steve Anton27ab0e52018-07-23 15:11:53 -0700459 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Ying Wangef3998f2019-12-09 13:06:53 +0100460 EXPECT_METRIC_THAT(
461 webrtc::metrics::Samples("WebRTC.PeerConnection.AddIceCandidate"),
462 ElementsAre(Pair(kAddIceCandidateFailNoRemoteDescription, 2)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700463}
464
Steve Antonc79268f2018-04-24 09:54:10 -0700465TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenPeerConnectionClosed) {
466 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
467
468 auto caller = CreatePeerConnectionWithAudioVideo();
469 auto callee = CreatePeerConnectionWithAudioVideo();
470
471 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
472
473 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
474 auto* audio_content = cricket::GetFirstAudioContent(
475 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700476 std::unique_ptr<IceCandidateInterface> jsep_candidate =
477 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700478
479 caller->pc()->Close();
480
Steve Anton27ab0e52018-07-23 15:11:53 -0700481 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700482}
483
Steve Anton46d926a2018-01-23 10:23:06 -0800484TEST_P(PeerConnectionIceTest, DuplicateIceCandidateIgnoredWhenAdded) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700485 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
486
487 auto caller = CreatePeerConnectionWithAudioVideo();
488 auto callee = CreatePeerConnectionWithAudioVideo();
489
490 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
491 ASSERT_TRUE(
492 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
493
494 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
495 caller->AddIceCandidate(&candidate);
496 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
497 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
498}
499
Tomas Gunnarsson27bc6e22021-02-12 13:16:26 +0100500// TODO(tommi): Re-enable after updating RTCPeerConnection-blockedPorts.html in
501// Chromium (the test needs setRemoteDescription to succeed for an invalid
502// candidate).
503TEST_P(PeerConnectionIceTest, DISABLED_ErrorOnInvalidRemoteIceCandidateAdded) {
Tomas Gunnarsson8cb97062021-02-08 18:57:04 +0100504 auto caller = CreatePeerConnectionWithAudioVideo();
505 auto callee = CreatePeerConnectionWithAudioVideo();
506 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
507 // Add a candidate to the remote description with a candidate that has an
508 // invalid address (port number == 2).
509 auto answer = callee->CreateAnswerAndSetAsLocal();
510 cricket::Candidate bad_candidate =
511 CreateLocalUdpCandidate(SocketAddress("2.2.2.2", 2));
512 RTC_LOG(LS_INFO) << "Bad candidate: " << bad_candidate.ToString();
513 AddCandidateToFirstTransport(&bad_candidate, answer.get());
514 // Now the call to SetRemoteDescription should fail.
515 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
516}
517
Steve Anton46d926a2018-01-23 10:23:06 -0800518TEST_P(PeerConnectionIceTest,
Steve Antonc79268f2018-04-24 09:54:10 -0700519 CannotRemoveIceCandidatesWhenPeerConnectionClosed) {
520 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
521
522 auto caller = CreatePeerConnectionWithAudioVideo();
523 auto callee = CreatePeerConnectionWithAudioVideo();
524
525 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
526
527 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
528 auto* audio_content = cricket::GetFirstAudioContent(
529 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700530 std::unique_ptr<IceCandidateInterface> ice_candidate =
531 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700532
Steve Anton27ab0e52018-07-23 15:11:53 -0700533 ASSERT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700534
535 caller->pc()->Close();
536
537 EXPECT_FALSE(caller->pc()->RemoveIceCandidates({candidate}));
538}
539
540TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700541 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
542 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
543
544 auto caller = CreatePeerConnectionWithAudioVideo();
545 auto callee = CreatePeerConnectionWithAudioVideo();
546
547 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
548 ASSERT_TRUE(
549 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
550
Artem Titovcfea2182021-08-10 01:22:31 +0200551 // `candidate.transport_name()` is empty.
Steve Antonf1c6db12017-10-13 11:13:35 -0700552 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton46d926a2018-01-23 10:23:06 -0800553 auto* audio_content = cricket::GetFirstAudioContent(
554 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700555 std::unique_ptr<IceCandidateInterface> ice_candidate =
556 CreateIceCandidate(audio_content->name, 0, candidate);
557 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700558 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
559}
560
Steve Anton46d926a2018-01-23 10:23:06 -0800561TEST_P(PeerConnectionIceTest, RemoveCandidateRemovesFromRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700562 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
563
564 auto caller = CreatePeerConnectionWithAudioVideo();
565 auto callee = CreatePeerConnectionWithAudioVideo();
566
567 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
568 ASSERT_TRUE(
569 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
570
571 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
572 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
573 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
574 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
575}
576
577// Test that if a candidate is added via AddIceCandidate and via an updated
578// remote description, then both candidates appear in the stored remote
579// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800580TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700581 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
582 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
583 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
584
585 auto caller = CreatePeerConnectionWithAudioVideo();
586 auto callee = CreatePeerConnectionWithAudioVideo();
587
588 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
589 ASSERT_TRUE(
590 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
591
Artem Titov880fa812021-07-30 22:30:23 +0200592 // Add one candidate via `AddIceCandidate`.
Steve Antonf1c6db12017-10-13 11:13:35 -0700593 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
594 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
595
596 // Add the second candidate via a reoffer.
597 auto offer = caller->CreateOffer();
598 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
599 AddCandidateToFirstTransport(&candidate2, offer.get());
600
601 // Expect both candidates to appear in the callee's remote description.
602 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
603 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
604}
605
606// The follow test verifies that SetLocal/RemoteDescription fails when an offer
607// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
608// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
609// pwd must be 22-256 characters and ufrag must be 4-256 characters.
Steve Anton46d926a2018-01-23 10:23:06 -0800610TEST_P(PeerConnectionIceTest, VerifyUfragPwdLength) {
Yves Gerey665174f2018-06-19 15:03:05 +0200611 auto set_local_description_with_ufrag_pwd_length = [this](int ufrag_len,
612 int pwd_len) {
613 auto pc = CreatePeerConnectionWithAudioVideo();
614 auto offer = pc->CreateOffer();
615 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
616 std::string(pwd_len, 'x'));
617 return pc->SetLocalDescription(std::move(offer));
618 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700619
Yves Gerey665174f2018-06-19 15:03:05 +0200620 auto set_remote_description_with_ufrag_pwd_length = [this](int ufrag_len,
621 int pwd_len) {
622 auto pc = CreatePeerConnectionWithAudioVideo();
623 auto offer = pc->CreateOffer();
624 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
625 std::string(pwd_len, 'x'));
626 return pc->SetRemoteDescription(std::move(offer));
627 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700628
629 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
630 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
631 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
632 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
633 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
634 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
635 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
636 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
637 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
638 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
639 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
640 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
641}
642
643::testing::AssertionResult AssertIpInCandidates(
644 const char* address_expr,
645 const char* candidates_expr,
646 const SocketAddress& address,
647 const std::vector<IceCandidateInterface*> candidates) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200648 rtc::StringBuilder candidate_hosts;
Steve Antonf1c6db12017-10-13 11:13:35 -0700649 for (const auto* candidate : candidates) {
650 const auto& candidate_ip = candidate->candidate().address().ipaddr();
651 if (candidate_ip == address.ipaddr()) {
652 return ::testing::AssertionSuccess();
653 }
Jonas Olssonabbe8412018-04-03 13:40:05 +0200654 candidate_hosts << "\n" << candidate_ip.ToString();
Steve Antonf1c6db12017-10-13 11:13:35 -0700655 }
656 return ::testing::AssertionFailure()
657 << address_expr << " (host " << address.HostAsURIString()
658 << ") not in " << candidates_expr
659 << " which have the following address hosts:" << candidate_hosts.str();
660}
661
Steve Anton46d926a2018-01-23 10:23:06 -0800662TEST_P(PeerConnectionIceTest, CandidatesGeneratedForEachLocalInterface) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700663 const SocketAddress kLocalAddress1("1.1.1.1", 0);
664 const SocketAddress kLocalAddress2("2.2.2.2", 0);
665
666 auto caller = CreatePeerConnectionWithAudioVideo();
667 caller->network()->AddInterface(kLocalAddress1);
668 caller->network()->AddInterface(kLocalAddress2);
669
670 caller->CreateOfferAndSetAsLocal();
671 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
672
673 auto candidates = caller->observer()->GetCandidatesByMline(0);
674 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
675 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
676}
677
Steve Anton46d926a2018-01-23 10:23:06 -0800678TEST_P(PeerConnectionIceTest, TrickledSingleCandidateAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700679 const SocketAddress kCallerAddress("1.1.1.1", 1111);
680
681 auto caller = CreatePeerConnectionWithAudioVideo();
682 auto callee = CreatePeerConnectionWithAudioVideo();
683
684 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
685
686 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
687 callee->AddIceCandidate(&candidate);
688 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
689 ASSERT_EQ(1u, candidates.size());
690 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
691 candidates[0]->candidate());
692}
693
Steve Anton46d926a2018-01-23 10:23:06 -0800694TEST_P(PeerConnectionIceTest, TwoTrickledCandidatesAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700695 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
696 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
697
698 auto caller = CreatePeerConnectionWithAudioVideo();
699 auto callee = CreatePeerConnectionWithAudioVideo();
700
701 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
702 ASSERT_TRUE(
703 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
704
705 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
706 caller->AddIceCandidate(&candidate1);
707
708 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
709 caller->AddIceCandidate(&candidate2);
710
711 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
712 ASSERT_EQ(2u, candidates.size());
713 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
714 candidates[0]->candidate());
715 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
716 candidates[1]->candidate());
717}
718
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100719TEST_P(PeerConnectionIceTest, AsyncAddIceCandidateIsAddedToRemoteDescription) {
720 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
721
722 auto caller = CreatePeerConnectionWithAudioVideo();
723 auto callee = CreatePeerConnectionWithAudioVideo();
724
725 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
726
727 auto jsep_candidate =
728 callee->CreateJsepCandidateForFirstTransport(&candidate);
729 bool operation_completed = false;
730 callee->pc()->AddIceCandidate(std::move(jsep_candidate),
731 [&operation_completed](RTCError result) {
732 EXPECT_TRUE(result.ok());
733 operation_completed = true;
734 });
735 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
736
737 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
738 ASSERT_EQ(1u, candidates.size());
739 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
740 candidates[0]->candidate());
741}
742
743TEST_P(PeerConnectionIceTest,
744 AsyncAddIceCandidateCompletesImmediatelyIfNoPendingOperation) {
745 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
746
747 auto caller = CreatePeerConnectionWithAudioVideo();
748 auto callee = CreatePeerConnectionWithAudioVideo();
749
750 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
751
752 auto jsep_candidate =
753 callee->CreateJsepCandidateForFirstTransport(&candidate);
754 bool operation_completed = false;
755 callee->pc()->AddIceCandidate(
756 std::move(jsep_candidate),
757 [&operation_completed](RTCError result) { operation_completed = true; });
758 EXPECT_TRUE(operation_completed);
759}
760
761TEST_P(PeerConnectionIceTest,
762 AsyncAddIceCandidateCompletesWhenPendingOperationCompletes) {
763 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
764
765 auto caller = CreatePeerConnectionWithAudioVideo();
766 auto callee = CreatePeerConnectionWithAudioVideo();
767
768 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
769
770 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200771 auto answer_observer =
772 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100773 callee->pc()->CreateAnswer(answer_observer, RTCOfferAnswerOptions());
774
775 auto jsep_candidate =
776 callee->CreateJsepCandidateForFirstTransport(&candidate);
777 bool operation_completed = false;
778 callee->pc()->AddIceCandidate(
779 std::move(jsep_candidate),
780 [&operation_completed](RTCError result) { operation_completed = true; });
781 // The operation will not be able to complete until we EXPECT_TRUE_WAIT()
782 // allowing CreateAnswer() to complete.
783 EXPECT_FALSE(operation_completed);
784 EXPECT_TRUE_WAIT(answer_observer->called(), kWaitTimeout);
785 // As soon as it does, AddIceCandidate() will execute without delay, so it
786 // must also have completed.
787 EXPECT_TRUE(operation_completed);
788}
789
790TEST_P(PeerConnectionIceTest,
791 AsyncAddIceCandidateFailsBeforeSetRemoteDescription) {
792 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
793
794 auto caller = CreatePeerConnectionWithAudioVideo();
795 std::unique_ptr<IceCandidateInterface> jsep_candidate =
796 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
797
798 bool operation_completed = false;
799 caller->pc()->AddIceCandidate(
800 std::move(jsep_candidate), [&operation_completed](RTCError result) {
801 EXPECT_FALSE(result.ok());
802 EXPECT_EQ(result.message(),
803 std::string("Error processing ICE candidate"));
804 operation_completed = true;
805 });
806 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
807}
808
809TEST_P(PeerConnectionIceTest,
810 AsyncAddIceCandidateFailsIfPeerConnectionDestroyed) {
811 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
812
813 auto caller = CreatePeerConnectionWithAudioVideo();
814 auto callee = CreatePeerConnectionWithAudioVideo();
815
816 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
817
818 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200819 auto answer_observer =
820 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100821 callee->pc()->CreateAnswer(answer_observer, RTCOfferAnswerOptions());
822
823 auto jsep_candidate =
824 callee->CreateJsepCandidateForFirstTransport(&candidate);
825 bool operation_completed = false;
826 callee->pc()->AddIceCandidate(
827 std::move(jsep_candidate), [&operation_completed](RTCError result) {
828 EXPECT_FALSE(result.ok());
829 EXPECT_EQ(
830 result.message(),
831 std::string(
832 "AddIceCandidate failed because the session was shut down"));
833 operation_completed = true;
834 });
835 // The operation will not be able to run until EXPECT_TRUE_WAIT(), giving us
836 // time to remove all references to the PeerConnection.
837 EXPECT_FALSE(operation_completed);
838 // This should delete the callee PC.
839 callee = nullptr;
840 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
841}
842
Steve Anton46d926a2018-01-23 10:23:06 -0800843TEST_P(PeerConnectionIceTest, LocalDescriptionUpdatedWhenContinualGathering) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700844 const SocketAddress kLocalAddress("1.1.1.1", 0);
845
846 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100847 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700848 config.continual_gathering_policy =
849 PeerConnectionInterface::GATHER_CONTINUALLY;
850 auto caller = CreatePeerConnectionWithAudioVideo(config);
851 caller->network()->AddInterface(kLocalAddress);
852
853 // Start ICE candidate gathering by setting the local offer.
854 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
855
856 // Since we're using continual gathering, we won't get "gathering done".
857 EXPECT_TRUE_WAIT(
858 caller->pc()->local_description()->candidates(0)->count() > 0,
859 kIceCandidatesTimeout);
860}
861
862// Test that when continual gathering is enabled, and a network interface goes
863// down, the candidate is signaled as removed and removed from the local
864// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800865TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700866 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
867 const SocketAddress kLocalAddress("1.1.1.1", 0);
868
869 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100870 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700871 config.continual_gathering_policy =
872 PeerConnectionInterface::GATHER_CONTINUALLY;
873 auto caller = CreatePeerConnectionWithAudioVideo(config);
874 caller->network()->AddInterface(kLocalAddress);
875
876 // Start ICE candidate gathering by setting the local offer.
877 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
878
879 EXPECT_TRUE_WAIT(
880 caller->pc()->local_description()->candidates(0)->count() > 0,
881 kIceCandidatesTimeout);
882
883 // Remove the only network interface, causing the PeerConnection to signal
884 // the removal of all candidates derived from this interface.
885 caller->network()->RemoveInterface(kLocalAddress);
886
887 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
888 kIceCandidatesTimeout);
889 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
890}
891
Steve Anton46d926a2018-01-23 10:23:06 -0800892TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700893 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
894 const SocketAddress kLocalAddress("1.1.1.1", 0);
895
896 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100897 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700898 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
899 auto caller = CreatePeerConnectionWithAudioVideo(config);
900 caller->network()->AddInterface(kLocalAddress);
901
902 // Start ICE candidate gathering by setting the local offer.
903 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
904
905 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
906
907 caller->network()->RemoveInterface(kLocalAddress);
908
909 // Verify that the local candidates are not removed;
910 rtc::Thread::Current()->ProcessMessages(1000);
911 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
912}
913
914// The following group tests that when an offer includes a new ufrag or pwd
915// (indicating an ICE restart) the old candidates are removed and new candidates
916// added to the remote description.
917
Steve Anton46d926a2018-01-23 10:23:06 -0800918TEST_P(PeerConnectionIceTest, IceRestartOfferClearsExistingCandidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700919 const SocketAddress kCallerAddress("1.1.1.1", 1111);
920
921 auto caller = CreatePeerConnectionWithAudioVideo();
922 auto callee = CreatePeerConnectionWithAudioVideo();
923
Amit Hilbuchae3df542019-01-07 12:13:08 -0800924 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700925 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
926 AddCandidateToFirstTransport(&candidate, offer.get());
927
928 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
929
930 RTCOfferAnswerOptions options;
931 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800932 ASSERT_TRUE(
933 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700934
935 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
936}
Steve Anton46d926a2018-01-23 10:23:06 -0800937TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700938 IceRestartOfferCandidateReplacesExistingCandidate) {
939 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
940 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
941
942 auto caller = CreatePeerConnectionWithAudioVideo();
943 auto callee = CreatePeerConnectionWithAudioVideo();
944
Amit Hilbuchae3df542019-01-07 12:13:08 -0800945 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700946 cricket::Candidate old_candidate =
947 CreateLocalUdpCandidate(kFirstCallerAddress);
948 AddCandidateToFirstTransport(&old_candidate, offer.get());
949
950 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
951
952 RTCOfferAnswerOptions options;
953 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800954 auto restart_offer = caller->CreateOfferAndSetAsLocal(options);
Steve Antonf1c6db12017-10-13 11:13:35 -0700955 cricket::Candidate new_candidate =
956 CreateLocalUdpCandidate(kRestartedCallerAddress);
957 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
958
959 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
960
961 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
962 ASSERT_EQ(1u, remote_candidates.size());
963 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
964 remote_candidates[0]->candidate());
965}
966
967// Test that if there is not an ICE restart (i.e., nothing changes), then the
968// answer to a later offer should have the same ufrag/pwd as the first answer.
Steve Anton46d926a2018-01-23 10:23:06 -0800969TEST_P(PeerConnectionIceTest, LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700970 auto caller = CreatePeerConnectionWithAudioVideo();
971 auto callee = CreatePeerConnectionWithAudioVideo();
972
973 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
974 ASSERT_TRUE(
975 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
976
977 // Re-offer.
978 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
979
980 auto answer = callee->CreateAnswer();
981 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
982 auto* local_transport_desc =
983 GetFirstTransportDescription(callee->pc()->local_description());
984
985 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
986 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
987}
988
Henrik Boström79b69802019-07-18 11:16:56 +0200989TEST_P(PeerConnectionIceTest, RestartIceGeneratesNewCredentials) {
990 auto caller = CreatePeerConnectionWithAudioVideo();
991 auto callee = CreatePeerConnectionWithAudioVideo();
992
993 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
994 auto initial_ice_credentials =
995 GetIceCredentials(caller->pc()->local_description());
996 caller->pc()->RestartIce();
997 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
998 auto restarted_ice_credentials =
999 GetIceCredentials(caller->pc()->local_description());
1000 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1001}
1002
1003TEST_P(PeerConnectionIceTest,
1004 RestartIceWhileLocalOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1005 auto caller = CreatePeerConnectionWithAudioVideo();
1006 auto callee = CreatePeerConnectionWithAudioVideo();
1007
1008 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1009 auto initial_ice_credentials =
1010 GetIceCredentials(caller->pc()->local_description());
Artem Titov880fa812021-07-30 22:30:23 +02001011 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001012 // offerer.
1013 caller->pc()->RestartIce();
1014 ASSERT_TRUE(
1015 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1016 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1017 auto restarted_ice_credentials =
1018 GetIceCredentials(caller->pc()->local_description());
1019 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1020}
1021
1022TEST_P(PeerConnectionIceTest,
1023 RestartIceWhileRemoteOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1024 auto caller = CreatePeerConnectionWithAudioVideo();
1025 auto callee = CreatePeerConnectionWithAudioVideo();
1026
1027 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1028 auto initial_ice_credentials =
1029 GetIceCredentials(caller->pc()->local_description());
1030 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001031 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001032 // answerer.
1033 caller->pc()->RestartIce();
1034 ASSERT_TRUE(
1035 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
1036 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1037 auto restarted_ice_credentials =
1038 GetIceCredentials(caller->pc()->local_description());
1039 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1040}
1041
1042TEST_P(PeerConnectionIceTest, RestartIceTriggeredByRemoteSide) {
1043 auto caller = CreatePeerConnectionWithAudioVideo();
1044 auto callee = CreatePeerConnectionWithAudioVideo();
1045
1046 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1047 auto initial_ice_credentials =
1048 GetIceCredentials(caller->pc()->local_description());
1049
Artem Titov880fa812021-07-30 22:30:23 +02001050 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001051 // restart ICE locally as well.
1052 callee->pc()->RestartIce();
1053 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1054
1055 auto restarted_ice_credentials =
1056 GetIceCredentials(caller->pc()->local_description());
1057 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1058}
1059
1060TEST_P(PeerConnectionIceTest, RestartIceCausesNegotiationNeeded) {
1061 auto caller = CreatePeerConnectionWithAudioVideo();
1062 auto callee = CreatePeerConnectionWithAudioVideo();
1063
1064 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001065 caller->observer()->clear_legacy_renegotiation_needed();
1066 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001067 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001068 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1069 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001070}
1071
1072// In Unified Plan, "onnegotiationneeded" is spec-compliant, including not
1073// firing multipe times in a row, or firing when returning to the stable
1074// signaling state if negotiation is still needed. In Plan B it fires any time
1075// something changes. As such, some tests are SdpSemantics-specific.
1076class PeerConnectionIceTestUnifiedPlan : public PeerConnectionIceBaseTest {
1077 protected:
1078 PeerConnectionIceTestUnifiedPlan()
1079 : PeerConnectionIceBaseTest(SdpSemantics::kUnifiedPlan) {}
1080};
1081
1082TEST_F(PeerConnectionIceTestUnifiedPlan,
1083 RestartIceWhileLocalOfferIsPendingCausesNegotiationNeededWhenStable) {
1084 auto caller = CreatePeerConnectionWithAudioVideo();
1085 auto callee = CreatePeerConnectionWithAudioVideo();
1086
1087 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001088 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001089 // offerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001090 caller->observer()->clear_legacy_renegotiation_needed();
1091 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001092 caller->pc()->RestartIce();
1093 // In Unified Plan, the event should not fire until we are back in the stable
1094 // signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001095 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1096 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001097 ASSERT_TRUE(
1098 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001099 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1100 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001101}
1102
1103TEST_F(PeerConnectionIceTestUnifiedPlan,
1104 RestartIceWhileRemoteOfferIsPendingCausesNegotiationNeededWhenStable) {
1105 auto caller = CreatePeerConnectionWithAudioVideo();
1106 auto callee = CreatePeerConnectionWithAudioVideo();
1107
1108 // Establish initial credentials as the caller.
1109 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1110 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001111 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001112 // answerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001113 caller->observer()->clear_legacy_renegotiation_needed();
1114 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001115 caller->pc()->RestartIce();
1116 // In Unified Plan, the event should not fire until we are back in the stable
1117 // signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001118 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1119 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001120 ASSERT_TRUE(
1121 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001122 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1123 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001124}
1125
1126TEST_F(PeerConnectionIceTestUnifiedPlan,
1127 RestartIceTriggeredByRemoteSideCauseNegotiationNotNeeded) {
1128 auto caller = CreatePeerConnectionWithAudioVideo();
1129 auto callee = CreatePeerConnectionWithAudioVideo();
1130
1131 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1132 // Local restart.
1133 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001134 caller->observer()->clear_legacy_renegotiation_needed();
1135 caller->observer()->clear_latest_negotiation_needed_event();
Artem Titov880fa812021-07-30 22:30:23 +02001136 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001137 // restart ICE locally as well.
1138 callee->pc()->RestartIce();
1139 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1140 // Having restarted ICE by the remote offer, we do not need to renegotiate ICE
1141 // credentials when back in the stable signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001142 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1143 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001144}
1145
1146TEST_F(PeerConnectionIceTestUnifiedPlan,
1147 RestartIceTwiceDoesNotFireNegotiationNeededTwice) {
1148 auto caller = CreatePeerConnectionWithAudioVideo();
1149 auto callee = CreatePeerConnectionWithAudioVideo();
1150
1151 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1152 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001153 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1154 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1155 caller->observer()->clear_legacy_renegotiation_needed();
1156 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001157 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001158 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1159 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001160}
1161
1162// In Plan B, "onnegotiationneeded" is not spec-compliant, firing based on if
1163// something changed rather than if negotiation is needed. In Unified Plan it
1164// fires according to spec. As such, some tests are SdpSemantics-specific.
1165class PeerConnectionIceTestPlanB : public PeerConnectionIceBaseTest {
1166 protected:
1167 PeerConnectionIceTestPlanB()
1168 : PeerConnectionIceBaseTest(SdpSemantics::kPlanB) {}
1169};
1170
1171TEST_F(PeerConnectionIceTestPlanB,
1172 RestartIceWhileOfferIsPendingCausesNegotiationNeededImmediately) {
1173 auto caller = CreatePeerConnectionWithAudioVideo();
1174 auto callee = CreatePeerConnectionWithAudioVideo();
1175
1176 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001177 caller->observer()->clear_legacy_renegotiation_needed();
1178 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001179 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001180 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1181 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1182 caller->observer()->clear_legacy_renegotiation_needed();
1183 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001184 ASSERT_TRUE(
1185 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1186 // In Plan B, the event fired early so we don't expect it to fire now. This is
1187 // not spec-compliant but follows the pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001188 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1189 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001190}
1191
1192TEST_F(PeerConnectionIceTestPlanB,
1193 RestartIceTwiceDoesFireNegotiationNeededTwice) {
1194 auto caller = CreatePeerConnectionWithAudioVideo();
1195 auto callee = CreatePeerConnectionWithAudioVideo();
1196
1197 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001198 caller->observer()->clear_legacy_renegotiation_needed();
1199 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001200 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001201 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1202 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1203 caller->observer()->clear_legacy_renegotiation_needed();
1204 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001205 caller->pc()->RestartIce();
1206 // In Plan B, the event fires every time something changed, even if we have
1207 // already fired the event. This is not spec-compliant but follows the same
1208 // pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001209 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1210 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001211}
1212
Steve Antonf1c6db12017-10-13 11:13:35 -07001213// The following parameterized test verifies that if an offer is sent with a
1214// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
1215// other side has initiated an ICE restart and generate a new ufrag and pwd.
1216// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
1217// a=ice-pwd attributes compared to the previous SDP from the peer, it
1218// indicates that ICE is restarting for this media stream."
1219
Steve Anton46d926a2018-01-23 10:23:06 -08001220class PeerConnectionIceUfragPwdAnswerTest
1221 : public PeerConnectionIceBaseTest,
1222 public ::testing::WithParamInterface<
1223 std::tuple<SdpSemantics, std::tuple<bool, bool>>> {
Steve Antonf1c6db12017-10-13 11:13:35 -07001224 protected:
Steve Anton46d926a2018-01-23 10:23:06 -08001225 PeerConnectionIceUfragPwdAnswerTest()
1226 : PeerConnectionIceBaseTest(std::get<0>(GetParam())) {
1227 auto param = std::get<1>(GetParam());
1228 offer_new_ufrag_ = std::get<0>(param);
1229 offer_new_pwd_ = std::get<1>(param);
Steve Antonf1c6db12017-10-13 11:13:35 -07001230 }
1231
1232 bool offer_new_ufrag_;
1233 bool offer_new_pwd_;
1234};
1235
Steve Anton46d926a2018-01-23 10:23:06 -08001236TEST_P(PeerConnectionIceUfragPwdAnswerTest, TestIncludedInAnswer) {
Steve Antonf1c6db12017-10-13 11:13:35 -07001237 auto caller = CreatePeerConnectionWithAudioVideo();
1238 auto callee = CreatePeerConnectionWithAudioVideo();
1239
1240 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1241 ASSERT_TRUE(
1242 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1243
1244 auto offer = caller->CreateOffer();
1245 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
1246 if (offer_new_ufrag_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001247 offer_transport_desc->ice_ufrag += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001248 }
1249 if (offer_new_pwd_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001250 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001251 }
1252
1253 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1254
1255 auto answer = callee->CreateAnswer();
1256 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
1257 auto* local_transport_desc =
1258 GetFirstTransportDescription(callee->pc()->local_description());
1259
1260 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
1261 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
1262}
1263
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001264INSTANTIATE_TEST_SUITE_P(
Steve Anton46d926a2018-01-23 10:23:06 -08001265 PeerConnectionIceTest,
1266 PeerConnectionIceUfragPwdAnswerTest,
1267 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
1268 Values(std::make_pair(true, true), // Both changed.
1269 std::make_pair(true, false), // Only ufrag changed.
1270 std::make_pair(false, true)))); // Only pwd changed.
Steve Antonf1c6db12017-10-13 11:13:35 -07001271
1272// Test that if an ICE restart is offered on one media section, then the answer
1273// will only change ICE ufrag/pwd for that section and keep the other sections
1274// the same.
1275// Note that this only works if we have disabled BUNDLE, otherwise all media
1276// sections will share the same transport.
Steve Anton46d926a2018-01-23 10:23:06 -08001277TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -07001278 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
1279 auto caller = CreatePeerConnectionWithAudioVideo();
1280 auto callee = CreatePeerConnectionWithAudioVideo();
1281
1282 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1283 ASSERT_TRUE(
1284 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1285
1286 RTCOfferAnswerOptions disable_bundle_options;
1287 disable_bundle_options.use_rtp_mux = false;
1288
1289 auto offer = caller->CreateOffer(disable_bundle_options);
1290
1291 // Signal ICE restart on the first media section.
1292 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
Steve Anton71ff0732020-01-24 16:28:15 -08001293 offer_transport_desc->ice_ufrag += "+new";
1294 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001295
1296 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1297
1298 auto answer = callee->CreateAnswer(disable_bundle_options);
1299 const auto& answer_transports = answer->description()->transport_infos();
1300 const auto& local_transports =
1301 callee->pc()->local_description()->description()->transport_infos();
1302
1303 EXPECT_NE(answer_transports[0].description.ice_ufrag,
1304 local_transports[0].description.ice_ufrag);
1305 EXPECT_NE(answer_transports[0].description.ice_pwd,
1306 local_transports[0].description.ice_pwd);
1307 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
1308 local_transports[1].description.ice_ufrag);
1309 EXPECT_EQ(answer_transports[1].description.ice_pwd,
1310 local_transports[1].description.ice_pwd);
1311}
1312
Qingsi Wange1692722017-11-29 13:27:20 -08001313// Test that when the initial offerer (caller) uses the lite implementation of
1314// ICE and the callee uses the full implementation, the caller takes the
1315// CONTROLLED role and the callee takes the CONTROLLING role. This is specified
1316// in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001317TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001318 OfferFromLiteIceControlledAndAnswerFromFullIceControlling) {
1319 auto caller = CreatePeerConnectionWithAudioVideo();
1320 auto callee = CreatePeerConnectionWithAudioVideo();
1321
1322 auto offer = caller->CreateOffer();
1323 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1324 ASSERT_TRUE(
1325 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1326 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1327
1328 auto answer = callee->CreateAnswer();
1329 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_FULL);
1330 ASSERT_TRUE(
1331 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1332 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1333
1334 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(caller));
1335 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(callee));
1336}
1337
1338// Test that when the caller and the callee both use the lite implementation of
1339// ICE, the initial offerer (caller) takes the CONTROLLING role and the callee
1340// takes the CONTROLLED role. This is specified in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001341TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001342 OfferFromLiteIceControllingAndAnswerFromLiteIceControlled) {
1343 auto caller = CreatePeerConnectionWithAudioVideo();
1344 auto callee = CreatePeerConnectionWithAudioVideo();
1345
1346 auto offer = caller->CreateOffer();
1347 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1348 ASSERT_TRUE(
1349 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1350 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1351
1352 auto answer = callee->CreateAnswer();
1353 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_LITE);
1354 ASSERT_TRUE(
1355 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1356 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1357
1358 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(caller));
1359 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(callee));
1360}
1361
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001362INSTANTIATE_TEST_SUITE_P(PeerConnectionIceTest,
1363 PeerConnectionIceTest,
1364 Values(SdpSemantics::kPlanB,
1365 SdpSemantics::kUnifiedPlan));
Steve Anton46d926a2018-01-23 10:23:06 -08001366
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001367class PeerConnectionIceConfigTest : public ::testing::Test {
Qingsi Wang4ff54432018-03-01 18:25:20 -08001368 protected:
1369 void SetUp() override {
1370 pc_factory_ = CreatePeerConnectionFactory(
1371 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
1372 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
Anders Carlsson67537952018-05-03 11:28:29 +02001373 CreateBuiltinAudioDecoderFactory(), CreateBuiltinVideoEncoderFactory(),
1374 CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
1375 nullptr /* audio_processing */);
Qingsi Wang4ff54432018-03-01 18:25:20 -08001376 }
1377 void CreatePeerConnection(const RTCConfiguration& config) {
1378 std::unique_ptr<cricket::FakePortAllocator> port_allocator(
1379 new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr));
1380 port_allocator_ = port_allocator.get();
1381 rtc::scoped_refptr<PeerConnectionInterface> pc(
Niels Möllerf06f9232018-08-07 12:32:18 +02001382 pc_factory_->CreatePeerConnection(config, std::move(port_allocator),
1383 nullptr /* cert_generator */,
1384 &observer_));
Qingsi Wang4ff54432018-03-01 18:25:20 -08001385 EXPECT_TRUE(pc.get());
Mirko Bonadei1c546052019-02-04 14:50:38 +01001386 pc_ = std::move(pc);
Qingsi Wang4ff54432018-03-01 18:25:20 -08001387 }
1388
1389 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_ = nullptr;
1390 rtc::scoped_refptr<PeerConnectionInterface> pc_ = nullptr;
1391 cricket::FakePortAllocator* port_allocator_ = nullptr;
1392
1393 MockPeerConnectionObserver observer_;
1394};
1395
1396TEST_F(PeerConnectionIceConfigTest, SetStunCandidateKeepaliveInterval) {
1397 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001398 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Qingsi Wang4ff54432018-03-01 18:25:20 -08001399 config.stun_candidate_keepalive_interval = 123;
1400 config.ice_candidate_pool_size = 1;
1401 CreatePeerConnection(config);
1402 ASSERT_NE(port_allocator_, nullptr);
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001403 absl::optional<int> actual_stun_keepalive_interval =
Qingsi Wang4ff54432018-03-01 18:25:20 -08001404 port_allocator_->stun_candidate_keepalive_interval();
1405 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 123);
1406 config.stun_candidate_keepalive_interval = 321;
Niels Möller2579f0c2019-08-19 09:58:17 +02001407 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
Qingsi Wang4ff54432018-03-01 18:25:20 -08001408 actual_stun_keepalive_interval =
1409 port_allocator_->stun_candidate_keepalive_interval();
1410 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 321);
1411}
1412
Derek Bailey6c127a12021-04-15 12:42:41 -07001413TEST_F(PeerConnectionIceConfigTest, SetStableWritableConnectionInterval) {
1414 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001415 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001416 config.stable_writable_connection_ping_interval_ms = 3500;
1417 CreatePeerConnection(config);
1418 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1419 EXPECT_EQ(pc_->GetConfiguration().stable_writable_connection_ping_interval_ms,
1420 config.stable_writable_connection_ping_interval_ms);
1421}
1422
1423TEST_F(PeerConnectionIceConfigTest,
1424 SetStableWritableConnectionInterval_FailsValidation) {
1425 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001426 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001427 CreatePeerConnection(config);
1428 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1429 config.stable_writable_connection_ping_interval_ms = 5000;
1430 config.ice_check_interval_strong_connectivity = 7500;
1431 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1432}
1433
1434TEST_F(PeerConnectionIceConfigTest,
1435 SetStableWritableConnectionInterval_DefaultValue_FailsValidation) {
1436 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001437 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001438 CreatePeerConnection(config);
1439 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1440 config.ice_check_interval_strong_connectivity = 2500;
1441 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1442 config.ice_check_interval_strong_connectivity = 2501;
1443 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1444}
1445
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001446TEST_P(PeerConnectionIceTest, IceCredentialsCreateOffer) {
1447 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001448 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001449 config.ice_candidate_pool_size = 1;
1450 auto pc = CreatePeerConnectionWithAudioVideo(config);
1451 ASSERT_NE(pc->port_allocator_, nullptr);
1452 auto offer = pc->CreateOffer();
1453 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1454 ASSERT_EQ(1u, credentials.size());
1455
1456 auto* desc = offer->description();
1457 for (const auto& content : desc->contents()) {
1458 auto* transport_info = desc->GetTransportInfoByName(content.name);
1459 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1460 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1461 }
1462}
1463
1464TEST_P(PeerConnectionIceTest, IceCredentialsCreateAnswer) {
1465 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001466 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001467 config.ice_candidate_pool_size = 1;
1468 auto pc = CreatePeerConnectionWithAudioVideo(config);
1469 ASSERT_NE(pc->port_allocator_, nullptr);
1470 auto offer = pc->CreateOffer();
1471 ASSERT_TRUE(pc->SetRemoteDescription(std::move(offer)));
1472 auto answer = pc->CreateAnswer();
1473
1474 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1475 ASSERT_EQ(1u, credentials.size());
1476
1477 auto* desc = answer->description();
1478 for (const auto& content : desc->contents()) {
1479 auto* transport_info = desc->GetTransportInfoByName(content.name);
1480 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1481 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1482 }
1483}
1484
Steve Antonec47b572020-01-24 14:53:37 -08001485// Regression test for https://bugs.chromium.org/p/webrtc/issues/detail?id=4728
1486TEST_P(PeerConnectionIceTest, CloseDoesNotTransitionGatheringStateToComplete) {
1487 auto pc = CreatePeerConnectionWithAudioVideo();
1488 pc->pc()->Close();
1489 EXPECT_FALSE(pc->IsIceGatheringDone());
1490 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
1491 pc->pc()->ice_gathering_state());
1492}
1493
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001494TEST_P(PeerConnectionIceTest, PrefersMidOverMLineIndex) {
1495 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
1496
1497 auto caller = CreatePeerConnectionWithAudioVideo();
1498 auto callee = CreatePeerConnectionWithAudioVideo();
1499
1500 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1501 ASSERT_TRUE(
1502 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1503
Artem Titovcfea2182021-08-10 01:22:31 +02001504 // `candidate.transport_name()` is empty.
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001505 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
1506 auto* audio_content = cricket::GetFirstAudioContent(
1507 caller->pc()->local_description()->description());
1508 std::unique_ptr<IceCandidateInterface> ice_candidate =
1509 CreateIceCandidate(audio_content->name, 65535, candidate);
1510 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
1511 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
1512}
1513
Steve Antonf1c6db12017-10-13 11:13:35 -07001514} // namespace webrtc