blob: ed64aa24ea550b70f3bcc26d039972c61846a915 [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
Harald Alvestrandc24a2182022-02-23 13:44:59 +000011#include <stddef.h>
12#include <stdint.h>
Mirko Bonadei317a1f02019-09-17 17:06:18 +020013
Harald Alvestrandc24a2182022-02-23 13:44:59 +000014#include <memory>
15#include <string>
16#include <tuple>
17#include <type_traits>
18#include <utility>
19#include <vector>
20
21#include "absl/types/optional.h"
22#include "api/audio/audio_mixer.h"
23#include "api/candidate.h"
24#include "api/ice_transport_interface.h"
25#include "api/jsep.h"
26#include "api/media_types.h"
27#include "api/peer_connection_interface.h"
28#include "api/rtc_error.h"
29#include "api/scoped_refptr.h"
30#include "modules/audio_device/include/audio_device.h"
31#include "modules/audio_processing/include/audio_processing.h"
Steve Anton10542f22019-01-11 09:11:00 -080032#include "p2p/base/fake_port_allocator.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000033#include "p2p/base/ice_transport_internal.h"
34#include "p2p/base/p2p_constants.h"
35#include "p2p/base/port.h"
36#include "p2p/base/port_allocator.h"
37#include "p2p/base/transport_description.h"
38#include "p2p/base/transport_info.h"
Steve Anton10542f22019-01-11 09:11:00 -080039#include "p2p/client/basic_port_allocator.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000040#include "pc/channel_interface.h"
41#include "pc/dtls_transport.h"
Steve Anton10542f22019-01-11 09:11:00 -080042#include "pc/media_session.h"
43#include "pc/peer_connection.h"
44#include "pc/peer_connection_wrapper.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000045#include "pc/rtp_transceiver.h"
Steve Anton10542f22019-01-11 09:11:00 -080046#include "pc/sdp_utils.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000047#include "pc/session_description.h"
48#include "rtc_base/checks.h"
49#include "rtc_base/ip_address.h"
50#include "rtc_base/logging.h"
51#include "rtc_base/net_helper.h"
52#include "rtc_base/ref_counted_object.h"
53#include "rtc_base/rtc_certificate_generator.h"
54#include "rtc_base/socket_address.h"
55#include "rtc_base/thread.h"
56#include "test/gtest.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070057#ifdef WEBRTC_ANDROID
Steve Anton10542f22019-01-11 09:11:00 -080058#include "pc/test/android_test_initializer.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070059#endif
Karl Wiberg1b0eae32017-10-17 14:48:54 +020060#include "api/audio_codecs/builtin_audio_decoder_factory.h"
61#include "api/audio_codecs/builtin_audio_encoder_factory.h"
Mirko Bonadei2ff3f492018-11-22 09:00:13 +010062#include "api/create_peerconnection_factory.h"
Steve Anton10542f22019-01-11 09:11:00 -080063#include "api/uma_metrics.h"
Anders Carlsson67537952018-05-03 11:28:29 +020064#include "api/video_codecs/builtin_video_decoder_factory.h"
65#include "api/video_codecs/builtin_video_encoder_factory.h"
Markus Handella1b82012021-05-26 18:56:30 +020066#include "pc/peer_connection_proxy.h"
Steve Anton10542f22019-01-11 09:11:00 -080067#include "pc/test/fake_audio_capture_module.h"
Henrik Boströmee6f4f62019-11-06 12:36:12 +010068#include "pc/test/mock_peer_connection_observers.h"
Steve Anton10542f22019-01-11 09:11:00 -080069#include "rtc_base/fake_network.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070070#include "rtc_base/gunit.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020071#include "rtc_base/strings/string_builder.h"
Steve Anton10542f22019-01-11 09:11:00 -080072#include "rtc_base/virtual_socket_server.h"
Mirko Bonadei17f48782018-09-28 08:51:10 +020073#include "system_wrappers/include/metrics.h"
Steve Antonb443dfe2019-03-05 14:09:49 -080074#include "test/gmock.h"
Steve Antonf1c6db12017-10-13 11:13:35 -070075
76namespace webrtc {
77
78using RTCConfiguration = PeerConnectionInterface::RTCConfiguration;
79using RTCOfferAnswerOptions = PeerConnectionInterface::RTCOfferAnswerOptions;
80using rtc::SocketAddress;
Steve Anton46d926a2018-01-23 10:23:06 -080081using ::testing::Combine;
Steve Antonb443dfe2019-03-05 14:09:49 -080082using ::testing::ElementsAre;
83using ::testing::Pair;
Steve Antonf1c6db12017-10-13 11:13:35 -070084using ::testing::Values;
85
86constexpr int kIceCandidatesTimeout = 10000;
Henrik Boströmee6f4f62019-11-06 12:36:12 +010087constexpr int64_t kWaitTimeout = 10000;
Steve Antonf1c6db12017-10-13 11:13:35 -070088
Steve Anton46d926a2018-01-23 10:23:06 -080089class PeerConnectionWrapperForIceTest : public PeerConnectionWrapper {
Steve Antonf1c6db12017-10-13 11:13:35 -070090 public:
91 using PeerConnectionWrapper::PeerConnectionWrapper;
92
Henrik Boströmee6f4f62019-11-06 12:36:12 +010093 std::unique_ptr<IceCandidateInterface> CreateJsepCandidateForFirstTransport(
94 cricket::Candidate* candidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -070095 RTC_DCHECK(pc()->remote_description());
96 const auto* desc = pc()->remote_description()->description();
97 RTC_DCHECK(desc->contents().size() > 0);
98 const auto& first_content = desc->contents()[0];
99 candidate->set_transport_name(first_content.name);
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100100 return CreateIceCandidate(first_content.name, -1, *candidate);
101 }
102
103 // Adds a new ICE candidate to the first transport.
104 bool AddIceCandidate(cricket::Candidate* candidate) {
105 return pc()->AddIceCandidate(
106 CreateJsepCandidateForFirstTransport(candidate).get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700107 }
108
109 // Returns ICE candidates from the remote session description.
110 std::vector<const IceCandidateInterface*>
111 GetIceCandidatesFromRemoteDescription() {
112 const SessionDescriptionInterface* sdesc = pc()->remote_description();
113 RTC_DCHECK(sdesc);
114 std::vector<const IceCandidateInterface*> candidates;
115 for (size_t mline_index = 0; mline_index < sdesc->number_of_mediasections();
116 mline_index++) {
117 const auto* candidate_collection = sdesc->candidates(mline_index);
118 for (size_t i = 0; i < candidate_collection->count(); i++) {
119 candidates.push_back(candidate_collection->at(i));
120 }
121 }
122 return candidates;
123 }
124
125 rtc::FakeNetworkManager* network() { return network_; }
126
127 void set_network(rtc::FakeNetworkManager* network) { network_ = network; }
128
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200129 // The port allocator used by this PC.
130 cricket::PortAllocator* port_allocator_;
131
Steve Antonf1c6db12017-10-13 11:13:35 -0700132 private:
133 rtc::FakeNetworkManager* network_;
134};
135
Steve Anton46d926a2018-01-23 10:23:06 -0800136class PeerConnectionIceBaseTest : public ::testing::Test {
Steve Antonf1c6db12017-10-13 11:13:35 -0700137 protected:
Steve Anton46d926a2018-01-23 10:23:06 -0800138 typedef std::unique_ptr<PeerConnectionWrapperForIceTest> WrapperPtr;
Steve Antonf1c6db12017-10-13 11:13:35 -0700139
Steve Anton46d926a2018-01-23 10:23:06 -0800140 explicit PeerConnectionIceBaseTest(SdpSemantics sdp_semantics)
141 : vss_(new rtc::VirtualSocketServer()),
142 main_(vss_.get()),
143 sdp_semantics_(sdp_semantics) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700144#ifdef WEBRTC_ANDROID
145 InitializeAndroidObjects();
146#endif
147 pc_factory_ = CreatePeerConnectionFactory(
148 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
Anders Carlsson67537952018-05-03 11:28:29 +0200149 rtc::scoped_refptr<AudioDeviceModule>(FakeAudioCaptureModule::Create()),
150 CreateBuiltinAudioEncoderFactory(), CreateBuiltinAudioDecoderFactory(),
151 CreateBuiltinVideoEncoderFactory(), CreateBuiltinVideoDecoderFactory(),
152 nullptr /* audio_mixer */, nullptr /* audio_processing */);
Steve Antonf1c6db12017-10-13 11:13:35 -0700153 }
154
155 WrapperPtr CreatePeerConnection() {
156 return CreatePeerConnection(RTCConfiguration());
157 }
158
159 WrapperPtr CreatePeerConnection(const RTCConfiguration& config) {
160 auto* fake_network = NewFakeNetwork();
161 auto port_allocator =
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200162 std::make_unique<cricket::BasicPortAllocator>(fake_network);
Steve Antonf1c6db12017-10-13 11:13:35 -0700163 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
164 cricket::PORTALLOCATOR_DISABLE_RELAY);
165 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
Steve Anton46d926a2018-01-23 10:23:06 -0800166 RTCConfiguration modified_config = config;
167 modified_config.sdp_semantics = sdp_semantics_;
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200168 auto observer = std::make_unique<MockPeerConnectionObserver>();
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200169 auto port_allocator_copy = port_allocator.get();
Steve Antonf1c6db12017-10-13 11:13:35 -0700170 auto pc = pc_factory_->CreatePeerConnection(
Steve Anton46d926a2018-01-23 10:23:06 -0800171 modified_config, std::move(port_allocator), nullptr, observer.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700172 if (!pc) {
173 return nullptr;
174 }
175
Yves Gerey4e933292018-10-31 15:36:05 +0100176 observer->SetPeerConnectionInterface(pc.get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200177 auto wrapper = std::make_unique<PeerConnectionWrapperForIceTest>(
Steve Antonf1c6db12017-10-13 11:13:35 -0700178 pc_factory_, pc, std::move(observer));
179 wrapper->set_network(fake_network);
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200180 wrapper->port_allocator_ = port_allocator_copy;
Steve Antonf1c6db12017-10-13 11:13:35 -0700181 return wrapper;
182 }
183
184 // Accepts the same arguments as CreatePeerConnection and adds default audio
185 // and video tracks.
186 template <typename... Args>
187 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
188 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
189 if (!wrapper) {
190 return nullptr;
191 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700192 wrapper->AddAudioTrack("a");
193 wrapper->AddVideoTrack("v");
Steve Antonf1c6db12017-10-13 11:13:35 -0700194 return wrapper;
195 }
196
197 cricket::Candidate CreateLocalUdpCandidate(
198 const rtc::SocketAddress& address) {
199 cricket::Candidate candidate;
200 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
201 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
202 candidate.set_address(address);
203 candidate.set_type(cricket::LOCAL_PORT_TYPE);
204 return candidate;
205 }
206
207 // Remove all ICE ufrag/pwd lines from the given session description.
208 void RemoveIceUfragPwd(SessionDescriptionInterface* sdesc) {
209 SetIceUfragPwd(sdesc, "", "");
210 }
211
212 // Sets all ICE ufrag/pwds on the given session description.
213 void SetIceUfragPwd(SessionDescriptionInterface* sdesc,
214 const std::string& ufrag,
215 const std::string& pwd) {
216 auto* desc = sdesc->description();
217 for (const auto& content : desc->contents()) {
218 auto* transport_info = desc->GetTransportInfoByName(content.name);
219 transport_info->description.ice_ufrag = ufrag;
220 transport_info->description.ice_pwd = pwd;
221 }
222 }
223
Qingsi Wange1692722017-11-29 13:27:20 -0800224 // Set ICE mode on the given session description.
225 void SetIceMode(SessionDescriptionInterface* sdesc,
226 const cricket::IceMode ice_mode) {
227 auto* desc = sdesc->description();
228 for (const auto& content : desc->contents()) {
229 auto* transport_info = desc->GetTransportInfoByName(content.name);
230 transport_info->description.ice_mode = ice_mode;
231 }
232 }
233
Steve Antonf1c6db12017-10-13 11:13:35 -0700234 cricket::TransportDescription* GetFirstTransportDescription(
235 SessionDescriptionInterface* sdesc) {
236 auto* desc = sdesc->description();
237 RTC_DCHECK(desc->contents().size() > 0);
238 auto* transport_info =
239 desc->GetTransportInfoByName(desc->contents()[0].name);
240 RTC_DCHECK(transport_info);
241 return &transport_info->description;
242 }
243
244 const cricket::TransportDescription* GetFirstTransportDescription(
245 const SessionDescriptionInterface* sdesc) {
246 auto* desc = sdesc->description();
247 RTC_DCHECK(desc->contents().size() > 0);
248 auto* transport_info =
249 desc->GetTransportInfoByName(desc->contents()[0].name);
250 RTC_DCHECK(transport_info);
251 return &transport_info->description;
252 }
253
Qingsi Wange1692722017-11-29 13:27:20 -0800254 // TODO(qingsi): Rewrite this method in terms of the standard IceTransport
255 // after it is implemented.
256 cricket::IceRole GetIceRole(const WrapperPtr& pc_wrapper_ptr) {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100257 auto* pc_proxy =
258 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
259 pc_wrapper_ptr->pc());
260 PeerConnection* pc = static_cast<PeerConnection*>(pc_proxy->internal());
Mirko Bonadei739baf02019-01-27 17:29:42 +0100261 for (const auto& transceiver : pc->GetTransceiversInternal()) {
Steve Anton69470252018-02-09 11:43:08 -0800262 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700263 auto dtls_transport = pc->LookupDtlsTransportByMidInternal(
Tomas Gunnarsson5411b172022-01-24 08:45:26 +0100264 transceiver->internal()->channel()->mid());
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700265 return dtls_transport->ice_transport()->internal()->GetIceRole();
Steve Anton46d926a2018-01-23 10:23:06 -0800266 }
267 }
Artem Titovd3251962021-11-15 16:57:07 +0100268 RTC_DCHECK_NOTREACHED();
Steve Anton46d926a2018-01-23 10:23:06 -0800269 return cricket::ICEROLE_UNKNOWN;
Qingsi Wange1692722017-11-29 13:27:20 -0800270 }
271
Henrik Boström79b69802019-07-18 11:16:56 +0200272 // Returns a list of (ufrag, pwd) pairs in the order that they appear in
Artem Titov880fa812021-07-30 22:30:23 +0200273 // `description`, or the empty list if `description` is null.
Henrik Boström79b69802019-07-18 11:16:56 +0200274 std::vector<std::pair<std::string, std::string>> GetIceCredentials(
275 const SessionDescriptionInterface* description) {
276 std::vector<std::pair<std::string, std::string>> ice_credentials;
277 if (!description)
278 return ice_credentials;
279 const auto* desc = description->description();
280 for (const auto& content_info : desc->contents()) {
281 const auto* transport_info =
282 desc->GetTransportInfoByName(content_info.name);
283 if (transport_info) {
284 ice_credentials.push_back(
285 std::make_pair(transport_info->description.ice_ufrag,
286 transport_info->description.ice_pwd));
287 }
288 }
289 return ice_credentials;
290 }
291
Steve Antonf1c6db12017-10-13 11:13:35 -0700292 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
293 SessionDescriptionInterface* sdesc) {
294 auto* desc = sdesc->description();
295 RTC_DCHECK(desc->contents().size() > 0);
296 const auto& first_content = desc->contents()[0];
297 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -0700298 std::unique_ptr<IceCandidateInterface> jsep_candidate =
299 CreateIceCandidate(first_content.name, 0, *candidate);
300 return sdesc->AddCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700301 }
302
303 rtc::FakeNetworkManager* NewFakeNetwork() {
304 // The PeerConnection's port allocator is tied to the PeerConnection's
305 // lifetime and expects the underlying NetworkManager to outlive it. That
306 // prevents us from having the PeerConnectionWrapper own the fake network.
307 // Therefore, the test fixture will own all the fake networks even though
308 // tests should access the fake network through the PeerConnectionWrapper.
309 auto* fake_network = new rtc::FakeNetworkManager();
310 fake_networks_.emplace_back(fake_network);
311 return fake_network;
312 }
313
314 std::unique_ptr<rtc::VirtualSocketServer> vss_;
315 rtc::AutoSocketServerThread main_;
316 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
317 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton46d926a2018-01-23 10:23:06 -0800318 const SdpSemantics sdp_semantics_;
319};
320
321class PeerConnectionIceTest
322 : public PeerConnectionIceBaseTest,
323 public ::testing::WithParamInterface<SdpSemantics> {
324 protected:
Harald Alvestrand76829d72018-07-18 23:24:36 +0200325 PeerConnectionIceTest() : PeerConnectionIceBaseTest(GetParam()) {
326 webrtc::metrics::Reset();
327 }
Steve Antonf1c6db12017-10-13 11:13:35 -0700328};
329
330::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
331 const char* b_expr,
332 const cricket::Candidate& a,
333 const cricket::Candidate& b) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200334 rtc::StringBuilder failure_info;
Steve Antonf1c6db12017-10-13 11:13:35 -0700335 if (a.component() != b.component()) {
336 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
337 }
338 if (a.protocol() != b.protocol()) {
339 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
340 }
341 if (a.address() != b.address()) {
342 failure_info << "\naddress: " << a.address().ToString()
343 << " != " << b.address().ToString();
344 }
345 if (a.type() != b.type()) {
346 failure_info << "\ntype: " << a.type() << " != " << b.type();
347 }
348 std::string failure_info_str = failure_info.str();
349 if (failure_info_str.empty()) {
350 return ::testing::AssertionSuccess();
351 } else {
352 return ::testing::AssertionFailure()
353 << a_expr << " and " << b_expr << " are not equal"
354 << failure_info_str;
355 }
356}
357
Steve Anton46d926a2018-01-23 10:23:06 -0800358TEST_P(PeerConnectionIceTest, OfferContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700359 const SocketAddress kLocalAddress("1.1.1.1", 0);
360
361 auto caller = CreatePeerConnectionWithAudioVideo();
362 caller->network()->AddInterface(kLocalAddress);
363
364 // Start ICE candidate gathering by setting the local offer.
365 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
366
367 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
368
369 auto offer = caller->CreateOffer();
370 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
371 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
372 offer->candidates(0)->count());
373 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
374 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
375 offer->candidates(1)->count());
376}
377
Steve Anton46d926a2018-01-23 10:23:06 -0800378TEST_P(PeerConnectionIceTest, AnswerContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700379 const SocketAddress kCallerAddress("1.1.1.1", 0);
380
381 auto caller = CreatePeerConnectionWithAudioVideo();
382 auto callee = CreatePeerConnectionWithAudioVideo();
383 caller->network()->AddInterface(kCallerAddress);
384
385 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
386 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
387
388 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
389
Steve Antondffead82018-02-06 10:31:29 -0800390 auto* answer = callee->pc()->local_description();
Steve Antonf1c6db12017-10-13 11:13:35 -0700391 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
392 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
393 answer->candidates(0)->count());
394 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
395 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
396 answer->candidates(1)->count());
397}
398
Steve Anton46d926a2018-01-23 10:23:06 -0800399TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700400 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
401 const SocketAddress kCallerAddress("1.1.1.1", 1111);
402
403 auto caller = CreatePeerConnectionWithAudioVideo();
404 auto callee = CreatePeerConnectionWithAudioVideo();
405
406 auto offer = caller->CreateOfferAndSetAsLocal();
407 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
408 AddCandidateToFirstTransport(&candidate, offer.get());
409
410 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
411 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
412 ASSERT_EQ(1u, remote_candidates.size());
413 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
414 remote_candidates[0]->candidate());
415}
416
Steve Anton46d926a2018-01-23 10:23:06 -0800417TEST_P(PeerConnectionIceTest, SetLocalDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700418 auto caller = CreatePeerConnectionWithAudioVideo();
419
420 auto offer = caller->CreateOffer();
421 RemoveIceUfragPwd(offer.get());
422
423 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
424}
425
Steve Anton46d926a2018-01-23 10:23:06 -0800426TEST_P(PeerConnectionIceTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700427 auto caller = CreatePeerConnectionWithAudioVideo();
428 auto callee = CreatePeerConnectionWithAudioVideo();
429
430 auto offer = caller->CreateOfferAndSetAsLocal();
431 RemoveIceUfragPwd(offer.get());
432
433 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
434}
435
Steve Antonf764cf42018-05-01 14:32:17 -0700436// Test that doing an offer/answer exchange with no transport (i.e., no data
437// channel or media) results in the ICE connection state staying at New.
438TEST_P(PeerConnectionIceTest,
439 OfferAnswerWithNoTransportsDoesNotChangeIceConnectionState) {
440 auto caller = CreatePeerConnection();
441 auto callee = CreatePeerConnection();
442
443 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
444
445 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
446 caller->pc()->ice_connection_state());
447 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
448 callee->pc()->ice_connection_state());
449}
450
Steve Antonf1c6db12017-10-13 11:13:35 -0700451// The following group tests that ICE candidates are not generated before
452// SetLocalDescription is called on a PeerConnection.
453
Steve Anton46d926a2018-01-23 10:23:06 -0800454TEST_P(PeerConnectionIceTest, NoIceCandidatesBeforeSetLocalDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700455 const SocketAddress kLocalAddress("1.1.1.1", 0);
456
457 auto caller = CreatePeerConnectionWithAudioVideo();
458 caller->network()->AddInterface(kLocalAddress);
459
460 // Pump for 1 second and verify that no candidates are generated.
461 rtc::Thread::Current()->ProcessMessages(1000);
462
463 EXPECT_EQ(0u, caller->observer()->candidates_.size());
464}
Steve Anton46d926a2018-01-23 10:23:06 -0800465TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700466 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
467 const SocketAddress kCallerAddress("1.1.1.1", 1111);
468
469 auto caller = CreatePeerConnectionWithAudioVideo();
470 auto callee = CreatePeerConnectionWithAudioVideo();
471 caller->network()->AddInterface(kCallerAddress);
472
473 auto offer = caller->CreateOfferAndSetAsLocal();
474 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
475 AddCandidateToFirstTransport(&candidate, offer.get());
476 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
477
478 // Pump for 1 second and verify that no candidates are generated.
479 rtc::Thread::Current()->ProcessMessages(1000);
480
481 EXPECT_EQ(0u, callee->observer()->candidates_.size());
482}
483
Steve Anton46d926a2018-01-23 10:23:06 -0800484TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenRemoteDescriptionNotSet) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700485 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
486
487 auto caller = CreatePeerConnectionWithAudioVideo();
488 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton27ab0e52018-07-23 15:11:53 -0700489 std::unique_ptr<IceCandidateInterface> jsep_candidate =
490 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
Steve Antonf1c6db12017-10-13 11:13:35 -0700491
Steve Anton27ab0e52018-07-23 15:11:53 -0700492 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700493
494 caller->CreateOfferAndSetAsLocal();
495
Steve Anton27ab0e52018-07-23 15:11:53 -0700496 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Ying Wangef3998f2019-12-09 13:06:53 +0100497 EXPECT_METRIC_THAT(
498 webrtc::metrics::Samples("WebRTC.PeerConnection.AddIceCandidate"),
499 ElementsAre(Pair(kAddIceCandidateFailNoRemoteDescription, 2)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700500}
501
Steve Antonc79268f2018-04-24 09:54:10 -0700502TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenPeerConnectionClosed) {
503 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
504
505 auto caller = CreatePeerConnectionWithAudioVideo();
506 auto callee = CreatePeerConnectionWithAudioVideo();
507
508 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
509
510 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
511 auto* audio_content = cricket::GetFirstAudioContent(
512 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700513 std::unique_ptr<IceCandidateInterface> jsep_candidate =
514 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700515
516 caller->pc()->Close();
517
Steve Anton27ab0e52018-07-23 15:11:53 -0700518 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700519}
520
Steve Anton46d926a2018-01-23 10:23:06 -0800521TEST_P(PeerConnectionIceTest, DuplicateIceCandidateIgnoredWhenAdded) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700522 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
523
524 auto caller = CreatePeerConnectionWithAudioVideo();
525 auto callee = CreatePeerConnectionWithAudioVideo();
526
527 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
528 ASSERT_TRUE(
529 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
530
531 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
532 caller->AddIceCandidate(&candidate);
533 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
534 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
535}
536
Tomas Gunnarsson27bc6e22021-02-12 13:16:26 +0100537// TODO(tommi): Re-enable after updating RTCPeerConnection-blockedPorts.html in
538// Chromium (the test needs setRemoteDescription to succeed for an invalid
539// candidate).
540TEST_P(PeerConnectionIceTest, DISABLED_ErrorOnInvalidRemoteIceCandidateAdded) {
Tomas Gunnarsson8cb97062021-02-08 18:57:04 +0100541 auto caller = CreatePeerConnectionWithAudioVideo();
542 auto callee = CreatePeerConnectionWithAudioVideo();
543 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
544 // Add a candidate to the remote description with a candidate that has an
545 // invalid address (port number == 2).
546 auto answer = callee->CreateAnswerAndSetAsLocal();
547 cricket::Candidate bad_candidate =
548 CreateLocalUdpCandidate(SocketAddress("2.2.2.2", 2));
549 RTC_LOG(LS_INFO) << "Bad candidate: " << bad_candidate.ToString();
550 AddCandidateToFirstTransport(&bad_candidate, answer.get());
551 // Now the call to SetRemoteDescription should fail.
552 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
553}
554
Steve Anton46d926a2018-01-23 10:23:06 -0800555TEST_P(PeerConnectionIceTest,
Steve Antonc79268f2018-04-24 09:54:10 -0700556 CannotRemoveIceCandidatesWhenPeerConnectionClosed) {
557 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
558
559 auto caller = CreatePeerConnectionWithAudioVideo();
560 auto callee = CreatePeerConnectionWithAudioVideo();
561
562 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
563
564 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
565 auto* audio_content = cricket::GetFirstAudioContent(
566 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700567 std::unique_ptr<IceCandidateInterface> ice_candidate =
568 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700569
Steve Anton27ab0e52018-07-23 15:11:53 -0700570 ASSERT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700571
572 caller->pc()->Close();
573
574 EXPECT_FALSE(caller->pc()->RemoveIceCandidates({candidate}));
575}
576
577TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700578 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
579 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
580
581 auto caller = CreatePeerConnectionWithAudioVideo();
582 auto callee = CreatePeerConnectionWithAudioVideo();
583
584 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
585 ASSERT_TRUE(
586 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
587
Artem Titovcfea2182021-08-10 01:22:31 +0200588 // `candidate.transport_name()` is empty.
Steve Antonf1c6db12017-10-13 11:13:35 -0700589 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton46d926a2018-01-23 10:23:06 -0800590 auto* audio_content = cricket::GetFirstAudioContent(
591 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700592 std::unique_ptr<IceCandidateInterface> ice_candidate =
593 CreateIceCandidate(audio_content->name, 0, candidate);
594 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700595 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
596}
597
Steve Anton46d926a2018-01-23 10:23:06 -0800598TEST_P(PeerConnectionIceTest, RemoveCandidateRemovesFromRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700599 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
600
601 auto caller = CreatePeerConnectionWithAudioVideo();
602 auto callee = CreatePeerConnectionWithAudioVideo();
603
604 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
605 ASSERT_TRUE(
606 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
607
608 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
609 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
610 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
611 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
612}
613
614// Test that if a candidate is added via AddIceCandidate and via an updated
615// remote description, then both candidates appear in the stored remote
616// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800617TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700618 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
619 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
620 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
621
622 auto caller = CreatePeerConnectionWithAudioVideo();
623 auto callee = CreatePeerConnectionWithAudioVideo();
624
625 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
626 ASSERT_TRUE(
627 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
628
Artem Titov880fa812021-07-30 22:30:23 +0200629 // Add one candidate via `AddIceCandidate`.
Steve Antonf1c6db12017-10-13 11:13:35 -0700630 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
631 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
632
633 // Add the second candidate via a reoffer.
634 auto offer = caller->CreateOffer();
635 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
636 AddCandidateToFirstTransport(&candidate2, offer.get());
637
638 // Expect both candidates to appear in the callee's remote description.
639 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
640 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
641}
642
643// The follow test verifies that SetLocal/RemoteDescription fails when an offer
644// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
645// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
646// pwd must be 22-256 characters and ufrag must be 4-256 characters.
Steve Anton46d926a2018-01-23 10:23:06 -0800647TEST_P(PeerConnectionIceTest, VerifyUfragPwdLength) {
Yves Gerey665174f2018-06-19 15:03:05 +0200648 auto set_local_description_with_ufrag_pwd_length = [this](int ufrag_len,
649 int pwd_len) {
650 auto pc = CreatePeerConnectionWithAudioVideo();
651 auto offer = pc->CreateOffer();
652 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
653 std::string(pwd_len, 'x'));
654 return pc->SetLocalDescription(std::move(offer));
655 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700656
Yves Gerey665174f2018-06-19 15:03:05 +0200657 auto set_remote_description_with_ufrag_pwd_length = [this](int ufrag_len,
658 int pwd_len) {
659 auto pc = CreatePeerConnectionWithAudioVideo();
660 auto offer = pc->CreateOffer();
661 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
662 std::string(pwd_len, 'x'));
663 return pc->SetRemoteDescription(std::move(offer));
664 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700665
666 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
667 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
668 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
669 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
670 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
671 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
672 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
673 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
674 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
675 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
676 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
677 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
678}
679
680::testing::AssertionResult AssertIpInCandidates(
681 const char* address_expr,
682 const char* candidates_expr,
683 const SocketAddress& address,
684 const std::vector<IceCandidateInterface*> candidates) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200685 rtc::StringBuilder candidate_hosts;
Steve Antonf1c6db12017-10-13 11:13:35 -0700686 for (const auto* candidate : candidates) {
687 const auto& candidate_ip = candidate->candidate().address().ipaddr();
688 if (candidate_ip == address.ipaddr()) {
689 return ::testing::AssertionSuccess();
690 }
Jonas Olssonabbe8412018-04-03 13:40:05 +0200691 candidate_hosts << "\n" << candidate_ip.ToString();
Steve Antonf1c6db12017-10-13 11:13:35 -0700692 }
693 return ::testing::AssertionFailure()
694 << address_expr << " (host " << address.HostAsURIString()
695 << ") not in " << candidates_expr
696 << " which have the following address hosts:" << candidate_hosts.str();
697}
698
Steve Anton46d926a2018-01-23 10:23:06 -0800699TEST_P(PeerConnectionIceTest, CandidatesGeneratedForEachLocalInterface) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700700 const SocketAddress kLocalAddress1("1.1.1.1", 0);
701 const SocketAddress kLocalAddress2("2.2.2.2", 0);
702
703 auto caller = CreatePeerConnectionWithAudioVideo();
704 caller->network()->AddInterface(kLocalAddress1);
705 caller->network()->AddInterface(kLocalAddress2);
706
707 caller->CreateOfferAndSetAsLocal();
708 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
709
710 auto candidates = caller->observer()->GetCandidatesByMline(0);
711 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
712 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
713}
714
Steve Anton46d926a2018-01-23 10:23:06 -0800715TEST_P(PeerConnectionIceTest, TrickledSingleCandidateAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700716 const SocketAddress kCallerAddress("1.1.1.1", 1111);
717
718 auto caller = CreatePeerConnectionWithAudioVideo();
719 auto callee = CreatePeerConnectionWithAudioVideo();
720
721 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
722
723 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
724 callee->AddIceCandidate(&candidate);
725 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
726 ASSERT_EQ(1u, candidates.size());
727 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
728 candidates[0]->candidate());
729}
730
Steve Anton46d926a2018-01-23 10:23:06 -0800731TEST_P(PeerConnectionIceTest, TwoTrickledCandidatesAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700732 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
733 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
734
735 auto caller = CreatePeerConnectionWithAudioVideo();
736 auto callee = CreatePeerConnectionWithAudioVideo();
737
738 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
739 ASSERT_TRUE(
740 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
741
742 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
743 caller->AddIceCandidate(&candidate1);
744
745 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
746 caller->AddIceCandidate(&candidate2);
747
748 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
749 ASSERT_EQ(2u, candidates.size());
750 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
751 candidates[0]->candidate());
752 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
753 candidates[1]->candidate());
754}
755
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100756TEST_P(PeerConnectionIceTest, AsyncAddIceCandidateIsAddedToRemoteDescription) {
757 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
758
759 auto caller = CreatePeerConnectionWithAudioVideo();
760 auto callee = CreatePeerConnectionWithAudioVideo();
761
762 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
763
764 auto jsep_candidate =
765 callee->CreateJsepCandidateForFirstTransport(&candidate);
766 bool operation_completed = false;
767 callee->pc()->AddIceCandidate(std::move(jsep_candidate),
768 [&operation_completed](RTCError result) {
769 EXPECT_TRUE(result.ok());
770 operation_completed = true;
771 });
772 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
773
774 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
775 ASSERT_EQ(1u, candidates.size());
776 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
777 candidates[0]->candidate());
778}
779
780TEST_P(PeerConnectionIceTest,
781 AsyncAddIceCandidateCompletesImmediatelyIfNoPendingOperation) {
782 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
783
784 auto caller = CreatePeerConnectionWithAudioVideo();
785 auto callee = CreatePeerConnectionWithAudioVideo();
786
787 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
788
789 auto jsep_candidate =
790 callee->CreateJsepCandidateForFirstTransport(&candidate);
791 bool operation_completed = false;
792 callee->pc()->AddIceCandidate(
793 std::move(jsep_candidate),
794 [&operation_completed](RTCError result) { operation_completed = true; });
795 EXPECT_TRUE(operation_completed);
796}
797
798TEST_P(PeerConnectionIceTest,
799 AsyncAddIceCandidateCompletesWhenPendingOperationCompletes) {
800 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
801
802 auto caller = CreatePeerConnectionWithAudioVideo();
803 auto callee = CreatePeerConnectionWithAudioVideo();
804
805 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
806
807 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200808 auto answer_observer =
809 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100810 callee->pc()->CreateAnswer(answer_observer, RTCOfferAnswerOptions());
811
812 auto jsep_candidate =
813 callee->CreateJsepCandidateForFirstTransport(&candidate);
814 bool operation_completed = false;
815 callee->pc()->AddIceCandidate(
816 std::move(jsep_candidate),
817 [&operation_completed](RTCError result) { operation_completed = true; });
818 // The operation will not be able to complete until we EXPECT_TRUE_WAIT()
819 // allowing CreateAnswer() to complete.
820 EXPECT_FALSE(operation_completed);
821 EXPECT_TRUE_WAIT(answer_observer->called(), kWaitTimeout);
822 // As soon as it does, AddIceCandidate() will execute without delay, so it
823 // must also have completed.
824 EXPECT_TRUE(operation_completed);
825}
826
827TEST_P(PeerConnectionIceTest,
828 AsyncAddIceCandidateFailsBeforeSetRemoteDescription) {
829 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
830
831 auto caller = CreatePeerConnectionWithAudioVideo();
832 std::unique_ptr<IceCandidateInterface> jsep_candidate =
833 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
834
835 bool operation_completed = false;
836 caller->pc()->AddIceCandidate(
837 std::move(jsep_candidate), [&operation_completed](RTCError result) {
838 EXPECT_FALSE(result.ok());
839 EXPECT_EQ(result.message(),
Henrik Boström347488e2022-01-21 15:18:08 +0100840 std::string("The remote description was null"));
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100841 operation_completed = true;
842 });
843 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
844}
845
846TEST_P(PeerConnectionIceTest,
847 AsyncAddIceCandidateFailsIfPeerConnectionDestroyed) {
848 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
849
850 auto caller = CreatePeerConnectionWithAudioVideo();
851 auto callee = CreatePeerConnectionWithAudioVideo();
852
853 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
854
855 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200856 auto answer_observer =
857 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100858 callee->pc()->CreateAnswer(answer_observer, RTCOfferAnswerOptions());
859
860 auto jsep_candidate =
861 callee->CreateJsepCandidateForFirstTransport(&candidate);
862 bool operation_completed = false;
863 callee->pc()->AddIceCandidate(
864 std::move(jsep_candidate), [&operation_completed](RTCError result) {
865 EXPECT_FALSE(result.ok());
866 EXPECT_EQ(
867 result.message(),
868 std::string(
869 "AddIceCandidate failed because the session was shut down"));
870 operation_completed = true;
871 });
872 // The operation will not be able to run until EXPECT_TRUE_WAIT(), giving us
873 // time to remove all references to the PeerConnection.
874 EXPECT_FALSE(operation_completed);
875 // This should delete the callee PC.
876 callee = nullptr;
877 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
878}
879
Steve Anton46d926a2018-01-23 10:23:06 -0800880TEST_P(PeerConnectionIceTest, LocalDescriptionUpdatedWhenContinualGathering) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700881 const SocketAddress kLocalAddress("1.1.1.1", 0);
882
883 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100884 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700885 config.continual_gathering_policy =
886 PeerConnectionInterface::GATHER_CONTINUALLY;
887 auto caller = CreatePeerConnectionWithAudioVideo(config);
888 caller->network()->AddInterface(kLocalAddress);
889
890 // Start ICE candidate gathering by setting the local offer.
891 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
892
893 // Since we're using continual gathering, we won't get "gathering done".
894 EXPECT_TRUE_WAIT(
895 caller->pc()->local_description()->candidates(0)->count() > 0,
896 kIceCandidatesTimeout);
897}
898
899// Test that when continual gathering is enabled, and a network interface goes
900// down, the candidate is signaled as removed and removed from the local
901// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800902TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700903 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
904 const SocketAddress kLocalAddress("1.1.1.1", 0);
905
906 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100907 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700908 config.continual_gathering_policy =
909 PeerConnectionInterface::GATHER_CONTINUALLY;
910 auto caller = CreatePeerConnectionWithAudioVideo(config);
911 caller->network()->AddInterface(kLocalAddress);
912
913 // Start ICE candidate gathering by setting the local offer.
914 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
915
916 EXPECT_TRUE_WAIT(
917 caller->pc()->local_description()->candidates(0)->count() > 0,
918 kIceCandidatesTimeout);
919
920 // Remove the only network interface, causing the PeerConnection to signal
921 // the removal of all candidates derived from this interface.
922 caller->network()->RemoveInterface(kLocalAddress);
923
924 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
925 kIceCandidatesTimeout);
926 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
927}
928
Steve Anton46d926a2018-01-23 10:23:06 -0800929TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700930 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
931 const SocketAddress kLocalAddress("1.1.1.1", 0);
932
933 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100934 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700935 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
936 auto caller = CreatePeerConnectionWithAudioVideo(config);
937 caller->network()->AddInterface(kLocalAddress);
938
939 // Start ICE candidate gathering by setting the local offer.
940 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
941
942 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
943
944 caller->network()->RemoveInterface(kLocalAddress);
945
946 // Verify that the local candidates are not removed;
947 rtc::Thread::Current()->ProcessMessages(1000);
948 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
949}
950
951// The following group tests that when an offer includes a new ufrag or pwd
952// (indicating an ICE restart) the old candidates are removed and new candidates
953// added to the remote description.
954
Steve Anton46d926a2018-01-23 10:23:06 -0800955TEST_P(PeerConnectionIceTest, IceRestartOfferClearsExistingCandidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700956 const SocketAddress kCallerAddress("1.1.1.1", 1111);
957
958 auto caller = CreatePeerConnectionWithAudioVideo();
959 auto callee = CreatePeerConnectionWithAudioVideo();
960
Amit Hilbuchae3df542019-01-07 12:13:08 -0800961 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700962 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
963 AddCandidateToFirstTransport(&candidate, offer.get());
964
965 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
966
967 RTCOfferAnswerOptions options;
968 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800969 ASSERT_TRUE(
970 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700971
972 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
973}
Steve Anton46d926a2018-01-23 10:23:06 -0800974TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700975 IceRestartOfferCandidateReplacesExistingCandidate) {
976 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
977 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
978
979 auto caller = CreatePeerConnectionWithAudioVideo();
980 auto callee = CreatePeerConnectionWithAudioVideo();
981
Amit Hilbuchae3df542019-01-07 12:13:08 -0800982 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700983 cricket::Candidate old_candidate =
984 CreateLocalUdpCandidate(kFirstCallerAddress);
985 AddCandidateToFirstTransport(&old_candidate, offer.get());
986
987 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
988
989 RTCOfferAnswerOptions options;
990 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800991 auto restart_offer = caller->CreateOfferAndSetAsLocal(options);
Steve Antonf1c6db12017-10-13 11:13:35 -0700992 cricket::Candidate new_candidate =
993 CreateLocalUdpCandidate(kRestartedCallerAddress);
994 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
995
996 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
997
998 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
999 ASSERT_EQ(1u, remote_candidates.size());
1000 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
1001 remote_candidates[0]->candidate());
1002}
1003
1004// Test that if there is not an ICE restart (i.e., nothing changes), then the
1005// answer to a later offer should have the same ufrag/pwd as the first answer.
Steve Anton46d926a2018-01-23 10:23:06 -08001006TEST_P(PeerConnectionIceTest, LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
Steve Antonf1c6db12017-10-13 11:13:35 -07001007 auto caller = CreatePeerConnectionWithAudioVideo();
1008 auto callee = CreatePeerConnectionWithAudioVideo();
1009
1010 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1011 ASSERT_TRUE(
1012 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1013
1014 // Re-offer.
1015 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1016
1017 auto answer = callee->CreateAnswer();
1018 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
1019 auto* local_transport_desc =
1020 GetFirstTransportDescription(callee->pc()->local_description());
1021
1022 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
1023 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
1024}
1025
Henrik Boström79b69802019-07-18 11:16:56 +02001026TEST_P(PeerConnectionIceTest, RestartIceGeneratesNewCredentials) {
1027 auto caller = CreatePeerConnectionWithAudioVideo();
1028 auto callee = CreatePeerConnectionWithAudioVideo();
1029
1030 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1031 auto initial_ice_credentials =
1032 GetIceCredentials(caller->pc()->local_description());
1033 caller->pc()->RestartIce();
1034 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1035 auto restarted_ice_credentials =
1036 GetIceCredentials(caller->pc()->local_description());
1037 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1038}
1039
1040TEST_P(PeerConnectionIceTest,
1041 RestartIceWhileLocalOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1042 auto caller = CreatePeerConnectionWithAudioVideo();
1043 auto callee = CreatePeerConnectionWithAudioVideo();
1044
1045 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1046 auto initial_ice_credentials =
1047 GetIceCredentials(caller->pc()->local_description());
Artem Titov880fa812021-07-30 22:30:23 +02001048 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001049 // offerer.
1050 caller->pc()->RestartIce();
1051 ASSERT_TRUE(
1052 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1053 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1054 auto restarted_ice_credentials =
1055 GetIceCredentials(caller->pc()->local_description());
1056 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1057}
1058
1059TEST_P(PeerConnectionIceTest,
1060 RestartIceWhileRemoteOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1061 auto caller = CreatePeerConnectionWithAudioVideo();
1062 auto callee = CreatePeerConnectionWithAudioVideo();
1063
1064 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1065 auto initial_ice_credentials =
1066 GetIceCredentials(caller->pc()->local_description());
1067 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001068 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001069 // answerer.
1070 caller->pc()->RestartIce();
1071 ASSERT_TRUE(
1072 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
1073 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1074 auto restarted_ice_credentials =
1075 GetIceCredentials(caller->pc()->local_description());
1076 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1077}
1078
1079TEST_P(PeerConnectionIceTest, RestartIceTriggeredByRemoteSide) {
1080 auto caller = CreatePeerConnectionWithAudioVideo();
1081 auto callee = CreatePeerConnectionWithAudioVideo();
1082
1083 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1084 auto initial_ice_credentials =
1085 GetIceCredentials(caller->pc()->local_description());
1086
Artem Titov880fa812021-07-30 22:30:23 +02001087 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001088 // restart ICE locally as well.
1089 callee->pc()->RestartIce();
1090 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1091
1092 auto restarted_ice_credentials =
1093 GetIceCredentials(caller->pc()->local_description());
1094 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1095}
1096
1097TEST_P(PeerConnectionIceTest, RestartIceCausesNegotiationNeeded) {
1098 auto caller = CreatePeerConnectionWithAudioVideo();
1099 auto callee = CreatePeerConnectionWithAudioVideo();
1100
1101 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001102 caller->observer()->clear_legacy_renegotiation_needed();
1103 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001104 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001105 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1106 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001107}
1108
1109// In Unified Plan, "onnegotiationneeded" is spec-compliant, including not
1110// firing multipe times in a row, or firing when returning to the stable
1111// signaling state if negotiation is still needed. In Plan B it fires any time
1112// something changes. As such, some tests are SdpSemantics-specific.
1113class PeerConnectionIceTestUnifiedPlan : public PeerConnectionIceBaseTest {
1114 protected:
1115 PeerConnectionIceTestUnifiedPlan()
1116 : PeerConnectionIceBaseTest(SdpSemantics::kUnifiedPlan) {}
1117};
1118
1119TEST_F(PeerConnectionIceTestUnifiedPlan,
1120 RestartIceWhileLocalOfferIsPendingCausesNegotiationNeededWhenStable) {
1121 auto caller = CreatePeerConnectionWithAudioVideo();
1122 auto callee = CreatePeerConnectionWithAudioVideo();
1123
1124 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001125 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001126 // offerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001127 caller->observer()->clear_legacy_renegotiation_needed();
1128 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001129 caller->pc()->RestartIce();
1130 // In Unified Plan, the event should not fire until we are back in the stable
1131 // signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001132 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1133 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001134 ASSERT_TRUE(
1135 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001136 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1137 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001138}
1139
1140TEST_F(PeerConnectionIceTestUnifiedPlan,
1141 RestartIceWhileRemoteOfferIsPendingCausesNegotiationNeededWhenStable) {
1142 auto caller = CreatePeerConnectionWithAudioVideo();
1143 auto callee = CreatePeerConnectionWithAudioVideo();
1144
1145 // Establish initial credentials as the caller.
1146 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1147 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001148 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001149 // answerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001150 caller->observer()->clear_legacy_renegotiation_needed();
1151 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001152 caller->pc()->RestartIce();
1153 // In Unified Plan, the event should not fire until we are back in the stable
1154 // signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001155 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1156 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001157 ASSERT_TRUE(
1158 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001159 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1160 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001161}
1162
1163TEST_F(PeerConnectionIceTestUnifiedPlan,
1164 RestartIceTriggeredByRemoteSideCauseNegotiationNotNeeded) {
1165 auto caller = CreatePeerConnectionWithAudioVideo();
1166 auto callee = CreatePeerConnectionWithAudioVideo();
1167
1168 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1169 // Local restart.
1170 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001171 caller->observer()->clear_legacy_renegotiation_needed();
1172 caller->observer()->clear_latest_negotiation_needed_event();
Artem Titov880fa812021-07-30 22:30:23 +02001173 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001174 // restart ICE locally as well.
1175 callee->pc()->RestartIce();
1176 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1177 // Having restarted ICE by the remote offer, we do not need to renegotiate ICE
1178 // credentials when back in the stable signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001179 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1180 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001181}
1182
1183TEST_F(PeerConnectionIceTestUnifiedPlan,
1184 RestartIceTwiceDoesNotFireNegotiationNeededTwice) {
1185 auto caller = CreatePeerConnectionWithAudioVideo();
1186 auto callee = CreatePeerConnectionWithAudioVideo();
1187
1188 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1189 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001190 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1191 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1192 caller->observer()->clear_legacy_renegotiation_needed();
1193 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001194 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001195 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1196 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001197}
1198
1199// In Plan B, "onnegotiationneeded" is not spec-compliant, firing based on if
1200// something changed rather than if negotiation is needed. In Unified Plan it
1201// fires according to spec. As such, some tests are SdpSemantics-specific.
1202class PeerConnectionIceTestPlanB : public PeerConnectionIceBaseTest {
1203 protected:
1204 PeerConnectionIceTestPlanB()
1205 : PeerConnectionIceBaseTest(SdpSemantics::kPlanB) {}
1206};
1207
1208TEST_F(PeerConnectionIceTestPlanB,
1209 RestartIceWhileOfferIsPendingCausesNegotiationNeededImmediately) {
1210 auto caller = CreatePeerConnectionWithAudioVideo();
1211 auto callee = CreatePeerConnectionWithAudioVideo();
1212
1213 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001214 caller->observer()->clear_legacy_renegotiation_needed();
1215 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001216 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001217 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1218 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1219 caller->observer()->clear_legacy_renegotiation_needed();
1220 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001221 ASSERT_TRUE(
1222 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1223 // In Plan B, the event fired early so we don't expect it to fire now. This is
1224 // not spec-compliant but follows the pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001225 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1226 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001227}
1228
1229TEST_F(PeerConnectionIceTestPlanB,
1230 RestartIceTwiceDoesFireNegotiationNeededTwice) {
1231 auto caller = CreatePeerConnectionWithAudioVideo();
1232 auto callee = CreatePeerConnectionWithAudioVideo();
1233
1234 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001235 caller->observer()->clear_legacy_renegotiation_needed();
1236 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001237 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001238 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1239 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1240 caller->observer()->clear_legacy_renegotiation_needed();
1241 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001242 caller->pc()->RestartIce();
1243 // In Plan B, the event fires every time something changed, even if we have
1244 // already fired the event. This is not spec-compliant but follows the same
1245 // pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001246 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1247 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001248}
1249
Steve Antonf1c6db12017-10-13 11:13:35 -07001250// The following parameterized test verifies that if an offer is sent with a
1251// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
1252// other side has initiated an ICE restart and generate a new ufrag and pwd.
1253// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
1254// a=ice-pwd attributes compared to the previous SDP from the peer, it
1255// indicates that ICE is restarting for this media stream."
1256
Steve Anton46d926a2018-01-23 10:23:06 -08001257class PeerConnectionIceUfragPwdAnswerTest
1258 : public PeerConnectionIceBaseTest,
1259 public ::testing::WithParamInterface<
1260 std::tuple<SdpSemantics, std::tuple<bool, bool>>> {
Steve Antonf1c6db12017-10-13 11:13:35 -07001261 protected:
Steve Anton46d926a2018-01-23 10:23:06 -08001262 PeerConnectionIceUfragPwdAnswerTest()
1263 : PeerConnectionIceBaseTest(std::get<0>(GetParam())) {
1264 auto param = std::get<1>(GetParam());
1265 offer_new_ufrag_ = std::get<0>(param);
1266 offer_new_pwd_ = std::get<1>(param);
Steve Antonf1c6db12017-10-13 11:13:35 -07001267 }
1268
1269 bool offer_new_ufrag_;
1270 bool offer_new_pwd_;
1271};
1272
Steve Anton46d926a2018-01-23 10:23:06 -08001273TEST_P(PeerConnectionIceUfragPwdAnswerTest, TestIncludedInAnswer) {
Steve Antonf1c6db12017-10-13 11:13:35 -07001274 auto caller = CreatePeerConnectionWithAudioVideo();
1275 auto callee = CreatePeerConnectionWithAudioVideo();
1276
1277 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1278 ASSERT_TRUE(
1279 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1280
1281 auto offer = caller->CreateOffer();
1282 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
1283 if (offer_new_ufrag_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001284 offer_transport_desc->ice_ufrag += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001285 }
1286 if (offer_new_pwd_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001287 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001288 }
1289
1290 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1291
1292 auto answer = callee->CreateAnswer();
1293 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
1294 auto* local_transport_desc =
1295 GetFirstTransportDescription(callee->pc()->local_description());
1296
1297 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
1298 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
1299}
1300
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001301INSTANTIATE_TEST_SUITE_P(
Steve Anton46d926a2018-01-23 10:23:06 -08001302 PeerConnectionIceTest,
1303 PeerConnectionIceUfragPwdAnswerTest,
1304 Combine(Values(SdpSemantics::kPlanB, SdpSemantics::kUnifiedPlan),
1305 Values(std::make_pair(true, true), // Both changed.
1306 std::make_pair(true, false), // Only ufrag changed.
1307 std::make_pair(false, true)))); // Only pwd changed.
Steve Antonf1c6db12017-10-13 11:13:35 -07001308
1309// Test that if an ICE restart is offered on one media section, then the answer
1310// will only change ICE ufrag/pwd for that section and keep the other sections
1311// the same.
1312// Note that this only works if we have disabled BUNDLE, otherwise all media
1313// sections will share the same transport.
Steve Anton46d926a2018-01-23 10:23:06 -08001314TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -07001315 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
1316 auto caller = CreatePeerConnectionWithAudioVideo();
1317 auto callee = CreatePeerConnectionWithAudioVideo();
1318
1319 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1320 ASSERT_TRUE(
1321 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1322
1323 RTCOfferAnswerOptions disable_bundle_options;
1324 disable_bundle_options.use_rtp_mux = false;
1325
1326 auto offer = caller->CreateOffer(disable_bundle_options);
1327
1328 // Signal ICE restart on the first media section.
1329 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
Steve Anton71ff0732020-01-24 16:28:15 -08001330 offer_transport_desc->ice_ufrag += "+new";
1331 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001332
1333 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1334
1335 auto answer = callee->CreateAnswer(disable_bundle_options);
1336 const auto& answer_transports = answer->description()->transport_infos();
1337 const auto& local_transports =
1338 callee->pc()->local_description()->description()->transport_infos();
1339
1340 EXPECT_NE(answer_transports[0].description.ice_ufrag,
1341 local_transports[0].description.ice_ufrag);
1342 EXPECT_NE(answer_transports[0].description.ice_pwd,
1343 local_transports[0].description.ice_pwd);
1344 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
1345 local_transports[1].description.ice_ufrag);
1346 EXPECT_EQ(answer_transports[1].description.ice_pwd,
1347 local_transports[1].description.ice_pwd);
1348}
1349
Qingsi Wange1692722017-11-29 13:27:20 -08001350// Test that when the initial offerer (caller) uses the lite implementation of
1351// ICE and the callee uses the full implementation, the caller takes the
1352// CONTROLLED role and the callee takes the CONTROLLING role. This is specified
1353// in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001354TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001355 OfferFromLiteIceControlledAndAnswerFromFullIceControlling) {
1356 auto caller = CreatePeerConnectionWithAudioVideo();
1357 auto callee = CreatePeerConnectionWithAudioVideo();
1358
1359 auto offer = caller->CreateOffer();
1360 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1361 ASSERT_TRUE(
1362 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1363 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1364
1365 auto answer = callee->CreateAnswer();
1366 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_FULL);
1367 ASSERT_TRUE(
1368 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1369 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1370
1371 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(caller));
1372 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(callee));
1373}
1374
1375// Test that when the caller and the callee both use the lite implementation of
1376// ICE, the initial offerer (caller) takes the CONTROLLING role and the callee
1377// takes the CONTROLLED role. This is specified in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001378TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001379 OfferFromLiteIceControllingAndAnswerFromLiteIceControlled) {
1380 auto caller = CreatePeerConnectionWithAudioVideo();
1381 auto callee = CreatePeerConnectionWithAudioVideo();
1382
1383 auto offer = caller->CreateOffer();
1384 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1385 ASSERT_TRUE(
1386 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1387 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1388
1389 auto answer = callee->CreateAnswer();
1390 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_LITE);
1391 ASSERT_TRUE(
1392 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1393 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1394
1395 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(caller));
1396 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(callee));
1397}
1398
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001399INSTANTIATE_TEST_SUITE_P(PeerConnectionIceTest,
1400 PeerConnectionIceTest,
1401 Values(SdpSemantics::kPlanB,
1402 SdpSemantics::kUnifiedPlan));
Steve Anton46d926a2018-01-23 10:23:06 -08001403
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001404class PeerConnectionIceConfigTest : public ::testing::Test {
Qingsi Wang4ff54432018-03-01 18:25:20 -08001405 protected:
1406 void SetUp() override {
1407 pc_factory_ = CreatePeerConnectionFactory(
1408 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
1409 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
Anders Carlsson67537952018-05-03 11:28:29 +02001410 CreateBuiltinAudioDecoderFactory(), CreateBuiltinVideoEncoderFactory(),
1411 CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
1412 nullptr /* audio_processing */);
Qingsi Wang4ff54432018-03-01 18:25:20 -08001413 }
1414 void CreatePeerConnection(const RTCConfiguration& config) {
1415 std::unique_ptr<cricket::FakePortAllocator> port_allocator(
1416 new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr));
1417 port_allocator_ = port_allocator.get();
1418 rtc::scoped_refptr<PeerConnectionInterface> pc(
Niels Möllerf06f9232018-08-07 12:32:18 +02001419 pc_factory_->CreatePeerConnection(config, std::move(port_allocator),
1420 nullptr /* cert_generator */,
1421 &observer_));
Qingsi Wang4ff54432018-03-01 18:25:20 -08001422 EXPECT_TRUE(pc.get());
Mirko Bonadei1c546052019-02-04 14:50:38 +01001423 pc_ = std::move(pc);
Qingsi Wang4ff54432018-03-01 18:25:20 -08001424 }
1425
1426 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_ = nullptr;
1427 rtc::scoped_refptr<PeerConnectionInterface> pc_ = nullptr;
1428 cricket::FakePortAllocator* port_allocator_ = nullptr;
1429
1430 MockPeerConnectionObserver observer_;
1431};
1432
1433TEST_F(PeerConnectionIceConfigTest, SetStunCandidateKeepaliveInterval) {
1434 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001435 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Qingsi Wang4ff54432018-03-01 18:25:20 -08001436 config.stun_candidate_keepalive_interval = 123;
1437 config.ice_candidate_pool_size = 1;
1438 CreatePeerConnection(config);
1439 ASSERT_NE(port_allocator_, nullptr);
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001440 absl::optional<int> actual_stun_keepalive_interval =
Qingsi Wang4ff54432018-03-01 18:25:20 -08001441 port_allocator_->stun_candidate_keepalive_interval();
1442 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 123);
1443 config.stun_candidate_keepalive_interval = 321;
Niels Möller2579f0c2019-08-19 09:58:17 +02001444 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
Qingsi Wang4ff54432018-03-01 18:25:20 -08001445 actual_stun_keepalive_interval =
1446 port_allocator_->stun_candidate_keepalive_interval();
1447 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 321);
1448}
1449
Derek Bailey6c127a12021-04-15 12:42:41 -07001450TEST_F(PeerConnectionIceConfigTest, SetStableWritableConnectionInterval) {
1451 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001452 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001453 config.stable_writable_connection_ping_interval_ms = 3500;
1454 CreatePeerConnection(config);
1455 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1456 EXPECT_EQ(pc_->GetConfiguration().stable_writable_connection_ping_interval_ms,
1457 config.stable_writable_connection_ping_interval_ms);
1458}
1459
1460TEST_F(PeerConnectionIceConfigTest,
1461 SetStableWritableConnectionInterval_FailsValidation) {
1462 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001463 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001464 CreatePeerConnection(config);
1465 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1466 config.stable_writable_connection_ping_interval_ms = 5000;
1467 config.ice_check_interval_strong_connectivity = 7500;
1468 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1469}
1470
1471TEST_F(PeerConnectionIceConfigTest,
1472 SetStableWritableConnectionInterval_DefaultValue_FailsValidation) {
1473 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001474 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001475 CreatePeerConnection(config);
1476 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1477 config.ice_check_interval_strong_connectivity = 2500;
1478 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1479 config.ice_check_interval_strong_connectivity = 2501;
1480 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1481}
1482
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001483TEST_P(PeerConnectionIceTest, IceCredentialsCreateOffer) {
1484 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001485 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001486 config.ice_candidate_pool_size = 1;
1487 auto pc = CreatePeerConnectionWithAudioVideo(config);
1488 ASSERT_NE(pc->port_allocator_, nullptr);
1489 auto offer = pc->CreateOffer();
1490 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1491 ASSERT_EQ(1u, credentials.size());
1492
1493 auto* desc = offer->description();
1494 for (const auto& content : desc->contents()) {
1495 auto* transport_info = desc->GetTransportInfoByName(content.name);
1496 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1497 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1498 }
1499}
1500
1501TEST_P(PeerConnectionIceTest, IceCredentialsCreateAnswer) {
1502 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001503 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001504 config.ice_candidate_pool_size = 1;
1505 auto pc = CreatePeerConnectionWithAudioVideo(config);
1506 ASSERT_NE(pc->port_allocator_, nullptr);
1507 auto offer = pc->CreateOffer();
1508 ASSERT_TRUE(pc->SetRemoteDescription(std::move(offer)));
1509 auto answer = pc->CreateAnswer();
1510
1511 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1512 ASSERT_EQ(1u, credentials.size());
1513
1514 auto* desc = answer->description();
1515 for (const auto& content : desc->contents()) {
1516 auto* transport_info = desc->GetTransportInfoByName(content.name);
1517 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1518 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1519 }
1520}
1521
Steve Antonec47b572020-01-24 14:53:37 -08001522// Regression test for https://bugs.chromium.org/p/webrtc/issues/detail?id=4728
1523TEST_P(PeerConnectionIceTest, CloseDoesNotTransitionGatheringStateToComplete) {
1524 auto pc = CreatePeerConnectionWithAudioVideo();
1525 pc->pc()->Close();
1526 EXPECT_FALSE(pc->IsIceGatheringDone());
1527 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
1528 pc->pc()->ice_gathering_state());
1529}
1530
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001531TEST_P(PeerConnectionIceTest, PrefersMidOverMLineIndex) {
1532 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
1533
1534 auto caller = CreatePeerConnectionWithAudioVideo();
1535 auto callee = CreatePeerConnectionWithAudioVideo();
1536
1537 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1538 ASSERT_TRUE(
1539 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1540
Artem Titovcfea2182021-08-10 01:22:31 +02001541 // `candidate.transport_name()` is empty.
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001542 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
1543 auto* audio_content = cricket::GetFirstAudioContent(
1544 caller->pc()->local_description()->description());
1545 std::unique_ptr<IceCandidateInterface> ice_candidate =
1546 CreateIceCandidate(audio_content->name, 65535, candidate);
1547 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
1548 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
1549}
1550
Steve Antonf1c6db12017-10-13 11:13:35 -07001551} // namespace webrtc