blob: e3d857deae0c5a16be45754050c69cc28781a5b4 [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"
Byoungchan Leed197e0b2022-05-30 23:59:55 +090049#include "rtc_base/internal/default_socket_server.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000050#include "rtc_base/ip_address.h"
51#include "rtc_base/logging.h"
52#include "rtc_base/net_helper.h"
Harald Alvestrandc24a2182022-02-23 13:44:59 +000053#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();
Byoungchan Leed197e0b2022-05-30 23:59:55 +0900161 auto port_allocator = std::make_unique<cricket::BasicPortAllocator>(
162 fake_network,
163 std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700164 port_allocator->set_flags(cricket::PORTALLOCATOR_DISABLE_TCP |
165 cricket::PORTALLOCATOR_DISABLE_RELAY);
166 port_allocator->set_step_delay(cricket::kMinimumStepDelay);
Steve Anton46d926a2018-01-23 10:23:06 -0800167 RTCConfiguration modified_config = config;
168 modified_config.sdp_semantics = sdp_semantics_;
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200169 auto observer = std::make_unique<MockPeerConnectionObserver>();
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200170 auto port_allocator_copy = port_allocator.get();
Florent Castelli72424402022-04-06 03:45:10 +0200171 PeerConnectionDependencies pc_dependencies(observer.get());
172 pc_dependencies.allocator = std::move(port_allocator);
173 auto result = pc_factory_->CreatePeerConnectionOrError(
174 modified_config, std::move(pc_dependencies));
175 if (!result.ok()) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700176 return nullptr;
177 }
178
Niels Möllerafb246b2022-04-20 14:26:50 +0200179 observer->SetPeerConnectionInterface(result.value().get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200180 auto wrapper = std::make_unique<PeerConnectionWrapperForIceTest>(
Florent Castelli72424402022-04-06 03:45:10 +0200181 pc_factory_, result.MoveValue(), std::move(observer));
Steve Antonf1c6db12017-10-13 11:13:35 -0700182 wrapper->set_network(fake_network);
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200183 wrapper->port_allocator_ = port_allocator_copy;
Steve Antonf1c6db12017-10-13 11:13:35 -0700184 return wrapper;
185 }
186
187 // Accepts the same arguments as CreatePeerConnection and adds default audio
188 // and video tracks.
189 template <typename... Args>
190 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
191 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
192 if (!wrapper) {
193 return nullptr;
194 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700195 wrapper->AddAudioTrack("a");
196 wrapper->AddVideoTrack("v");
Steve Antonf1c6db12017-10-13 11:13:35 -0700197 return wrapper;
198 }
199
200 cricket::Candidate CreateLocalUdpCandidate(
201 const rtc::SocketAddress& address) {
202 cricket::Candidate candidate;
203 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
204 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
205 candidate.set_address(address);
206 candidate.set_type(cricket::LOCAL_PORT_TYPE);
207 return candidate;
208 }
209
210 // Remove all ICE ufrag/pwd lines from the given session description.
211 void RemoveIceUfragPwd(SessionDescriptionInterface* sdesc) {
212 SetIceUfragPwd(sdesc, "", "");
213 }
214
215 // Sets all ICE ufrag/pwds on the given session description.
216 void SetIceUfragPwd(SessionDescriptionInterface* sdesc,
217 const std::string& ufrag,
218 const std::string& pwd) {
219 auto* desc = sdesc->description();
220 for (const auto& content : desc->contents()) {
221 auto* transport_info = desc->GetTransportInfoByName(content.name);
222 transport_info->description.ice_ufrag = ufrag;
223 transport_info->description.ice_pwd = pwd;
224 }
225 }
226
Qingsi Wange1692722017-11-29 13:27:20 -0800227 // Set ICE mode on the given session description.
228 void SetIceMode(SessionDescriptionInterface* sdesc,
229 const cricket::IceMode ice_mode) {
230 auto* desc = sdesc->description();
231 for (const auto& content : desc->contents()) {
232 auto* transport_info = desc->GetTransportInfoByName(content.name);
233 transport_info->description.ice_mode = ice_mode;
234 }
235 }
236
Steve Antonf1c6db12017-10-13 11:13:35 -0700237 cricket::TransportDescription* GetFirstTransportDescription(
238 SessionDescriptionInterface* sdesc) {
239 auto* desc = sdesc->description();
240 RTC_DCHECK(desc->contents().size() > 0);
241 auto* transport_info =
242 desc->GetTransportInfoByName(desc->contents()[0].name);
243 RTC_DCHECK(transport_info);
244 return &transport_info->description;
245 }
246
247 const cricket::TransportDescription* GetFirstTransportDescription(
248 const SessionDescriptionInterface* sdesc) {
249 auto* desc = sdesc->description();
250 RTC_DCHECK(desc->contents().size() > 0);
251 auto* transport_info =
252 desc->GetTransportInfoByName(desc->contents()[0].name);
253 RTC_DCHECK(transport_info);
254 return &transport_info->description;
255 }
256
Qingsi Wange1692722017-11-29 13:27:20 -0800257 // TODO(qingsi): Rewrite this method in terms of the standard IceTransport
258 // after it is implemented.
259 cricket::IceRole GetIceRole(const WrapperPtr& pc_wrapper_ptr) {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100260 auto* pc_proxy =
261 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
262 pc_wrapper_ptr->pc());
263 PeerConnection* pc = static_cast<PeerConnection*>(pc_proxy->internal());
Mirko Bonadei739baf02019-01-27 17:29:42 +0100264 for (const auto& transceiver : pc->GetTransceiversInternal()) {
Steve Anton69470252018-02-09 11:43:08 -0800265 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700266 auto dtls_transport = pc->LookupDtlsTransportByMidInternal(
Tomas Gunnarsson5411b172022-01-24 08:45:26 +0100267 transceiver->internal()->channel()->mid());
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700268 return dtls_transport->ice_transport()->internal()->GetIceRole();
Steve Anton46d926a2018-01-23 10:23:06 -0800269 }
270 }
Artem Titovd3251962021-11-15 16:57:07 +0100271 RTC_DCHECK_NOTREACHED();
Steve Anton46d926a2018-01-23 10:23:06 -0800272 return cricket::ICEROLE_UNKNOWN;
Qingsi Wange1692722017-11-29 13:27:20 -0800273 }
274
Henrik Boström79b69802019-07-18 11:16:56 +0200275 // Returns a list of (ufrag, pwd) pairs in the order that they appear in
Artem Titov880fa812021-07-30 22:30:23 +0200276 // `description`, or the empty list if `description` is null.
Henrik Boström79b69802019-07-18 11:16:56 +0200277 std::vector<std::pair<std::string, std::string>> GetIceCredentials(
278 const SessionDescriptionInterface* description) {
279 std::vector<std::pair<std::string, std::string>> ice_credentials;
280 if (!description)
281 return ice_credentials;
282 const auto* desc = description->description();
283 for (const auto& content_info : desc->contents()) {
284 const auto* transport_info =
285 desc->GetTransportInfoByName(content_info.name);
286 if (transport_info) {
287 ice_credentials.push_back(
288 std::make_pair(transport_info->description.ice_ufrag,
289 transport_info->description.ice_pwd));
290 }
291 }
292 return ice_credentials;
293 }
294
Steve Antonf1c6db12017-10-13 11:13:35 -0700295 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
296 SessionDescriptionInterface* sdesc) {
297 auto* desc = sdesc->description();
298 RTC_DCHECK(desc->contents().size() > 0);
299 const auto& first_content = desc->contents()[0];
300 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -0700301 std::unique_ptr<IceCandidateInterface> jsep_candidate =
302 CreateIceCandidate(first_content.name, 0, *candidate);
303 return sdesc->AddCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700304 }
305
306 rtc::FakeNetworkManager* NewFakeNetwork() {
307 // The PeerConnection's port allocator is tied to the PeerConnection's
308 // lifetime and expects the underlying NetworkManager to outlive it. That
309 // prevents us from having the PeerConnectionWrapper own the fake network.
310 // Therefore, the test fixture will own all the fake networks even though
311 // tests should access the fake network through the PeerConnectionWrapper.
312 auto* fake_network = new rtc::FakeNetworkManager();
313 fake_networks_.emplace_back(fake_network);
314 return fake_network;
315 }
316
317 std::unique_ptr<rtc::VirtualSocketServer> vss_;
318 rtc::AutoSocketServerThread main_;
319 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
320 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton46d926a2018-01-23 10:23:06 -0800321 const SdpSemantics sdp_semantics_;
322};
323
324class PeerConnectionIceTest
325 : public PeerConnectionIceBaseTest,
326 public ::testing::WithParamInterface<SdpSemantics> {
327 protected:
Harald Alvestrand76829d72018-07-18 23:24:36 +0200328 PeerConnectionIceTest() : PeerConnectionIceBaseTest(GetParam()) {
329 webrtc::metrics::Reset();
330 }
Steve Antonf1c6db12017-10-13 11:13:35 -0700331};
332
333::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
334 const char* b_expr,
335 const cricket::Candidate& a,
336 const cricket::Candidate& b) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200337 rtc::StringBuilder failure_info;
Steve Antonf1c6db12017-10-13 11:13:35 -0700338 if (a.component() != b.component()) {
339 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
340 }
341 if (a.protocol() != b.protocol()) {
342 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
343 }
344 if (a.address() != b.address()) {
345 failure_info << "\naddress: " << a.address().ToString()
346 << " != " << b.address().ToString();
347 }
348 if (a.type() != b.type()) {
349 failure_info << "\ntype: " << a.type() << " != " << b.type();
350 }
351 std::string failure_info_str = failure_info.str();
352 if (failure_info_str.empty()) {
353 return ::testing::AssertionSuccess();
354 } else {
355 return ::testing::AssertionFailure()
356 << a_expr << " and " << b_expr << " are not equal"
357 << failure_info_str;
358 }
359}
360
Steve Anton46d926a2018-01-23 10:23:06 -0800361TEST_P(PeerConnectionIceTest, OfferContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700362 const SocketAddress kLocalAddress("1.1.1.1", 0);
363
364 auto caller = CreatePeerConnectionWithAudioVideo();
365 caller->network()->AddInterface(kLocalAddress);
366
367 // Start ICE candidate gathering by setting the local offer.
368 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
369
370 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
371
372 auto offer = caller->CreateOffer();
373 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
374 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
375 offer->candidates(0)->count());
376 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
377 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
378 offer->candidates(1)->count());
379}
380
Steve Anton46d926a2018-01-23 10:23:06 -0800381TEST_P(PeerConnectionIceTest, AnswerContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700382 const SocketAddress kCallerAddress("1.1.1.1", 0);
383
384 auto caller = CreatePeerConnectionWithAudioVideo();
385 auto callee = CreatePeerConnectionWithAudioVideo();
386 caller->network()->AddInterface(kCallerAddress);
387
388 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
389 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
390
391 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
392
Steve Antondffead82018-02-06 10:31:29 -0800393 auto* answer = callee->pc()->local_description();
Steve Antonf1c6db12017-10-13 11:13:35 -0700394 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
395 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
396 answer->candidates(0)->count());
397 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
398 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
399 answer->candidates(1)->count());
400}
401
Steve Anton46d926a2018-01-23 10:23:06 -0800402TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700403 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
404 const SocketAddress kCallerAddress("1.1.1.1", 1111);
405
406 auto caller = CreatePeerConnectionWithAudioVideo();
407 auto callee = CreatePeerConnectionWithAudioVideo();
408
409 auto offer = caller->CreateOfferAndSetAsLocal();
410 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
411 AddCandidateToFirstTransport(&candidate, offer.get());
412
413 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
414 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
415 ASSERT_EQ(1u, remote_candidates.size());
416 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
417 remote_candidates[0]->candidate());
418}
419
Steve Anton46d926a2018-01-23 10:23:06 -0800420TEST_P(PeerConnectionIceTest, SetLocalDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700421 auto caller = CreatePeerConnectionWithAudioVideo();
422
423 auto offer = caller->CreateOffer();
424 RemoveIceUfragPwd(offer.get());
425
426 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
427}
428
Steve Anton46d926a2018-01-23 10:23:06 -0800429TEST_P(PeerConnectionIceTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700430 auto caller = CreatePeerConnectionWithAudioVideo();
431 auto callee = CreatePeerConnectionWithAudioVideo();
432
433 auto offer = caller->CreateOfferAndSetAsLocal();
434 RemoveIceUfragPwd(offer.get());
435
436 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
437}
438
Steve Antonf764cf42018-05-01 14:32:17 -0700439// Test that doing an offer/answer exchange with no transport (i.e., no data
440// channel or media) results in the ICE connection state staying at New.
441TEST_P(PeerConnectionIceTest,
442 OfferAnswerWithNoTransportsDoesNotChangeIceConnectionState) {
443 auto caller = CreatePeerConnection();
444 auto callee = CreatePeerConnection();
445
446 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
447
448 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
449 caller->pc()->ice_connection_state());
450 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
451 callee->pc()->ice_connection_state());
452}
453
Steve Antonf1c6db12017-10-13 11:13:35 -0700454// The following group tests that ICE candidates are not generated before
455// SetLocalDescription is called on a PeerConnection.
456
Steve Anton46d926a2018-01-23 10:23:06 -0800457TEST_P(PeerConnectionIceTest, NoIceCandidatesBeforeSetLocalDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700458 const SocketAddress kLocalAddress("1.1.1.1", 0);
459
460 auto caller = CreatePeerConnectionWithAudioVideo();
461 caller->network()->AddInterface(kLocalAddress);
462
463 // Pump for 1 second and verify that no candidates are generated.
464 rtc::Thread::Current()->ProcessMessages(1000);
465
466 EXPECT_EQ(0u, caller->observer()->candidates_.size());
467}
Steve Anton46d926a2018-01-23 10:23:06 -0800468TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700469 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
470 const SocketAddress kCallerAddress("1.1.1.1", 1111);
471
472 auto caller = CreatePeerConnectionWithAudioVideo();
473 auto callee = CreatePeerConnectionWithAudioVideo();
474 caller->network()->AddInterface(kCallerAddress);
475
476 auto offer = caller->CreateOfferAndSetAsLocal();
477 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
478 AddCandidateToFirstTransport(&candidate, offer.get());
479 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
480
481 // Pump for 1 second and verify that no candidates are generated.
482 rtc::Thread::Current()->ProcessMessages(1000);
483
484 EXPECT_EQ(0u, callee->observer()->candidates_.size());
485}
486
Steve Anton46d926a2018-01-23 10:23:06 -0800487TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenRemoteDescriptionNotSet) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700488 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
489
490 auto caller = CreatePeerConnectionWithAudioVideo();
491 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton27ab0e52018-07-23 15:11:53 -0700492 std::unique_ptr<IceCandidateInterface> jsep_candidate =
493 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
Steve Antonf1c6db12017-10-13 11:13:35 -0700494
Steve Anton27ab0e52018-07-23 15:11:53 -0700495 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700496
497 caller->CreateOfferAndSetAsLocal();
498
Steve Anton27ab0e52018-07-23 15:11:53 -0700499 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Ying Wangef3998f2019-12-09 13:06:53 +0100500 EXPECT_METRIC_THAT(
501 webrtc::metrics::Samples("WebRTC.PeerConnection.AddIceCandidate"),
502 ElementsAre(Pair(kAddIceCandidateFailNoRemoteDescription, 2)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700503}
504
Steve Antonc79268f2018-04-24 09:54:10 -0700505TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenPeerConnectionClosed) {
506 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
507
508 auto caller = CreatePeerConnectionWithAudioVideo();
509 auto callee = CreatePeerConnectionWithAudioVideo();
510
511 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
512
513 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
514 auto* audio_content = cricket::GetFirstAudioContent(
515 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700516 std::unique_ptr<IceCandidateInterface> jsep_candidate =
517 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700518
519 caller->pc()->Close();
520
Steve Anton27ab0e52018-07-23 15:11:53 -0700521 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700522}
523
Steve Anton46d926a2018-01-23 10:23:06 -0800524TEST_P(PeerConnectionIceTest, DuplicateIceCandidateIgnoredWhenAdded) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700525 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
526
527 auto caller = CreatePeerConnectionWithAudioVideo();
528 auto callee = CreatePeerConnectionWithAudioVideo();
529
530 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
531 ASSERT_TRUE(
532 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
533
534 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
535 caller->AddIceCandidate(&candidate);
536 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
537 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
538}
539
Tomas Gunnarsson27bc6e22021-02-12 13:16:26 +0100540// TODO(tommi): Re-enable after updating RTCPeerConnection-blockedPorts.html in
541// Chromium (the test needs setRemoteDescription to succeed for an invalid
542// candidate).
543TEST_P(PeerConnectionIceTest, DISABLED_ErrorOnInvalidRemoteIceCandidateAdded) {
Tomas Gunnarsson8cb97062021-02-08 18:57:04 +0100544 auto caller = CreatePeerConnectionWithAudioVideo();
545 auto callee = CreatePeerConnectionWithAudioVideo();
546 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
547 // Add a candidate to the remote description with a candidate that has an
548 // invalid address (port number == 2).
549 auto answer = callee->CreateAnswerAndSetAsLocal();
550 cricket::Candidate bad_candidate =
551 CreateLocalUdpCandidate(SocketAddress("2.2.2.2", 2));
552 RTC_LOG(LS_INFO) << "Bad candidate: " << bad_candidate.ToString();
553 AddCandidateToFirstTransport(&bad_candidate, answer.get());
554 // Now the call to SetRemoteDescription should fail.
555 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
556}
557
Steve Anton46d926a2018-01-23 10:23:06 -0800558TEST_P(PeerConnectionIceTest,
Steve Antonc79268f2018-04-24 09:54:10 -0700559 CannotRemoveIceCandidatesWhenPeerConnectionClosed) {
560 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
561
562 auto caller = CreatePeerConnectionWithAudioVideo();
563 auto callee = CreatePeerConnectionWithAudioVideo();
564
565 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
566
567 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
568 auto* audio_content = cricket::GetFirstAudioContent(
569 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700570 std::unique_ptr<IceCandidateInterface> ice_candidate =
571 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700572
Steve Anton27ab0e52018-07-23 15:11:53 -0700573 ASSERT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700574
575 caller->pc()->Close();
576
577 EXPECT_FALSE(caller->pc()->RemoveIceCandidates({candidate}));
578}
579
580TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700581 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
582 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
583
584 auto caller = CreatePeerConnectionWithAudioVideo();
585 auto callee = CreatePeerConnectionWithAudioVideo();
586
587 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
588 ASSERT_TRUE(
589 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
590
Artem Titovcfea2182021-08-10 01:22:31 +0200591 // `candidate.transport_name()` is empty.
Steve Antonf1c6db12017-10-13 11:13:35 -0700592 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton46d926a2018-01-23 10:23:06 -0800593 auto* audio_content = cricket::GetFirstAudioContent(
594 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700595 std::unique_ptr<IceCandidateInterface> ice_candidate =
596 CreateIceCandidate(audio_content->name, 0, candidate);
597 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700598 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
599}
600
Steve Anton46d926a2018-01-23 10:23:06 -0800601TEST_P(PeerConnectionIceTest, RemoveCandidateRemovesFromRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700602 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
603
604 auto caller = CreatePeerConnectionWithAudioVideo();
605 auto callee = CreatePeerConnectionWithAudioVideo();
606
607 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
608 ASSERT_TRUE(
609 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
610
611 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
612 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
613 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
614 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
615}
616
617// Test that if a candidate is added via AddIceCandidate and via an updated
618// remote description, then both candidates appear in the stored remote
619// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800620TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700621 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
622 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
623 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
624
625 auto caller = CreatePeerConnectionWithAudioVideo();
626 auto callee = CreatePeerConnectionWithAudioVideo();
627
628 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
629 ASSERT_TRUE(
630 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
631
Artem Titov880fa812021-07-30 22:30:23 +0200632 // Add one candidate via `AddIceCandidate`.
Steve Antonf1c6db12017-10-13 11:13:35 -0700633 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
634 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
635
636 // Add the second candidate via a reoffer.
637 auto offer = caller->CreateOffer();
638 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
639 AddCandidateToFirstTransport(&candidate2, offer.get());
640
641 // Expect both candidates to appear in the callee's remote description.
642 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
643 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
644}
645
646// The follow test verifies that SetLocal/RemoteDescription fails when an offer
647// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
648// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
649// pwd must be 22-256 characters and ufrag must be 4-256 characters.
Steve Anton46d926a2018-01-23 10:23:06 -0800650TEST_P(PeerConnectionIceTest, VerifyUfragPwdLength) {
Yves Gerey665174f2018-06-19 15:03:05 +0200651 auto set_local_description_with_ufrag_pwd_length = [this](int ufrag_len,
652 int pwd_len) {
653 auto pc = CreatePeerConnectionWithAudioVideo();
654 auto offer = pc->CreateOffer();
655 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
656 std::string(pwd_len, 'x'));
657 return pc->SetLocalDescription(std::move(offer));
658 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700659
Yves Gerey665174f2018-06-19 15:03:05 +0200660 auto set_remote_description_with_ufrag_pwd_length = [this](int ufrag_len,
661 int pwd_len) {
662 auto pc = CreatePeerConnectionWithAudioVideo();
663 auto offer = pc->CreateOffer();
664 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
665 std::string(pwd_len, 'x'));
666 return pc->SetRemoteDescription(std::move(offer));
667 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700668
669 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
670 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
671 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
672 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
673 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
674 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
675 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
676 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
677 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
678 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
679 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
680 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
681}
682
683::testing::AssertionResult AssertIpInCandidates(
684 const char* address_expr,
685 const char* candidates_expr,
686 const SocketAddress& address,
687 const std::vector<IceCandidateInterface*> candidates) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200688 rtc::StringBuilder candidate_hosts;
Steve Antonf1c6db12017-10-13 11:13:35 -0700689 for (const auto* candidate : candidates) {
690 const auto& candidate_ip = candidate->candidate().address().ipaddr();
691 if (candidate_ip == address.ipaddr()) {
692 return ::testing::AssertionSuccess();
693 }
Jonas Olssonabbe8412018-04-03 13:40:05 +0200694 candidate_hosts << "\n" << candidate_ip.ToString();
Steve Antonf1c6db12017-10-13 11:13:35 -0700695 }
696 return ::testing::AssertionFailure()
697 << address_expr << " (host " << address.HostAsURIString()
698 << ") not in " << candidates_expr
699 << " which have the following address hosts:" << candidate_hosts.str();
700}
701
Steve Anton46d926a2018-01-23 10:23:06 -0800702TEST_P(PeerConnectionIceTest, CandidatesGeneratedForEachLocalInterface) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700703 const SocketAddress kLocalAddress1("1.1.1.1", 0);
704 const SocketAddress kLocalAddress2("2.2.2.2", 0);
705
706 auto caller = CreatePeerConnectionWithAudioVideo();
707 caller->network()->AddInterface(kLocalAddress1);
708 caller->network()->AddInterface(kLocalAddress2);
709
710 caller->CreateOfferAndSetAsLocal();
711 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
712
713 auto candidates = caller->observer()->GetCandidatesByMline(0);
714 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
715 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
716}
717
Steve Anton46d926a2018-01-23 10:23:06 -0800718TEST_P(PeerConnectionIceTest, TrickledSingleCandidateAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700719 const SocketAddress kCallerAddress("1.1.1.1", 1111);
720
721 auto caller = CreatePeerConnectionWithAudioVideo();
722 auto callee = CreatePeerConnectionWithAudioVideo();
723
724 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
725
726 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
727 callee->AddIceCandidate(&candidate);
728 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
729 ASSERT_EQ(1u, candidates.size());
730 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
731 candidates[0]->candidate());
732}
733
Steve Anton46d926a2018-01-23 10:23:06 -0800734TEST_P(PeerConnectionIceTest, TwoTrickledCandidatesAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700735 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
736 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
737
738 auto caller = CreatePeerConnectionWithAudioVideo();
739 auto callee = CreatePeerConnectionWithAudioVideo();
740
741 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
742 ASSERT_TRUE(
743 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
744
745 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
746 caller->AddIceCandidate(&candidate1);
747
748 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
749 caller->AddIceCandidate(&candidate2);
750
751 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
752 ASSERT_EQ(2u, candidates.size());
753 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
754 candidates[0]->candidate());
755 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
756 candidates[1]->candidate());
757}
758
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100759TEST_P(PeerConnectionIceTest, AsyncAddIceCandidateIsAddedToRemoteDescription) {
760 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
761
762 auto caller = CreatePeerConnectionWithAudioVideo();
763 auto callee = CreatePeerConnectionWithAudioVideo();
764
765 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
766
767 auto jsep_candidate =
768 callee->CreateJsepCandidateForFirstTransport(&candidate);
769 bool operation_completed = false;
770 callee->pc()->AddIceCandidate(std::move(jsep_candidate),
771 [&operation_completed](RTCError result) {
772 EXPECT_TRUE(result.ok());
773 operation_completed = true;
774 });
775 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
776
777 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
778 ASSERT_EQ(1u, candidates.size());
779 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
780 candidates[0]->candidate());
781}
782
783TEST_P(PeerConnectionIceTest,
784 AsyncAddIceCandidateCompletesImmediatelyIfNoPendingOperation) {
785 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
786
787 auto caller = CreatePeerConnectionWithAudioVideo();
788 auto callee = CreatePeerConnectionWithAudioVideo();
789
790 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
791
792 auto jsep_candidate =
793 callee->CreateJsepCandidateForFirstTransport(&candidate);
794 bool operation_completed = false;
795 callee->pc()->AddIceCandidate(
796 std::move(jsep_candidate),
797 [&operation_completed](RTCError result) { operation_completed = true; });
798 EXPECT_TRUE(operation_completed);
799}
800
801TEST_P(PeerConnectionIceTest,
802 AsyncAddIceCandidateCompletesWhenPendingOperationCompletes) {
803 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
804
805 auto caller = CreatePeerConnectionWithAudioVideo();
806 auto callee = CreatePeerConnectionWithAudioVideo();
807
808 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
809
810 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200811 auto answer_observer =
812 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Niels Möllerafb246b2022-04-20 14:26:50 +0200813 callee->pc()->CreateAnswer(answer_observer.get(), RTCOfferAnswerOptions());
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100814
815 auto jsep_candidate =
816 callee->CreateJsepCandidateForFirstTransport(&candidate);
817 bool operation_completed = false;
818 callee->pc()->AddIceCandidate(
819 std::move(jsep_candidate),
820 [&operation_completed](RTCError result) { operation_completed = true; });
821 // The operation will not be able to complete until we EXPECT_TRUE_WAIT()
822 // allowing CreateAnswer() to complete.
823 EXPECT_FALSE(operation_completed);
824 EXPECT_TRUE_WAIT(answer_observer->called(), kWaitTimeout);
825 // As soon as it does, AddIceCandidate() will execute without delay, so it
826 // must also have completed.
827 EXPECT_TRUE(operation_completed);
828}
829
830TEST_P(PeerConnectionIceTest,
831 AsyncAddIceCandidateFailsBeforeSetRemoteDescription) {
832 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
833
834 auto caller = CreatePeerConnectionWithAudioVideo();
835 std::unique_ptr<IceCandidateInterface> jsep_candidate =
836 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
837
838 bool operation_completed = false;
839 caller->pc()->AddIceCandidate(
840 std::move(jsep_candidate), [&operation_completed](RTCError result) {
841 EXPECT_FALSE(result.ok());
842 EXPECT_EQ(result.message(),
Henrik Boström347488e2022-01-21 15:18:08 +0100843 std::string("The remote description was null"));
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100844 operation_completed = true;
845 });
846 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
847}
848
849TEST_P(PeerConnectionIceTest,
850 AsyncAddIceCandidateFailsIfPeerConnectionDestroyed) {
851 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
852
853 auto caller = CreatePeerConnectionWithAudioVideo();
854 auto callee = CreatePeerConnectionWithAudioVideo();
855
856 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
857
858 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200859 auto answer_observer =
860 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Niels Möllerafb246b2022-04-20 14:26:50 +0200861 callee->pc()->CreateAnswer(answer_observer.get(), RTCOfferAnswerOptions());
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100862
863 auto jsep_candidate =
864 callee->CreateJsepCandidateForFirstTransport(&candidate);
865 bool operation_completed = false;
866 callee->pc()->AddIceCandidate(
867 std::move(jsep_candidate), [&operation_completed](RTCError result) {
868 EXPECT_FALSE(result.ok());
869 EXPECT_EQ(
870 result.message(),
871 std::string(
872 "AddIceCandidate failed because the session was shut down"));
873 operation_completed = true;
874 });
875 // The operation will not be able to run until EXPECT_TRUE_WAIT(), giving us
876 // time to remove all references to the PeerConnection.
877 EXPECT_FALSE(operation_completed);
878 // This should delete the callee PC.
879 callee = nullptr;
880 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
881}
882
Steve Anton46d926a2018-01-23 10:23:06 -0800883TEST_P(PeerConnectionIceTest, LocalDescriptionUpdatedWhenContinualGathering) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700884 const SocketAddress kLocalAddress("1.1.1.1", 0);
885
886 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100887 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700888 config.continual_gathering_policy =
889 PeerConnectionInterface::GATHER_CONTINUALLY;
890 auto caller = CreatePeerConnectionWithAudioVideo(config);
891 caller->network()->AddInterface(kLocalAddress);
892
893 // Start ICE candidate gathering by setting the local offer.
894 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
895
896 // Since we're using continual gathering, we won't get "gathering done".
897 EXPECT_TRUE_WAIT(
898 caller->pc()->local_description()->candidates(0)->count() > 0,
899 kIceCandidatesTimeout);
900}
901
902// Test that when continual gathering is enabled, and a network interface goes
903// down, the candidate is signaled as removed and removed from the local
904// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800905TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700906 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
907 const SocketAddress kLocalAddress("1.1.1.1", 0);
908
909 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100910 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700911 config.continual_gathering_policy =
912 PeerConnectionInterface::GATHER_CONTINUALLY;
913 auto caller = CreatePeerConnectionWithAudioVideo(config);
914 caller->network()->AddInterface(kLocalAddress);
915
916 // Start ICE candidate gathering by setting the local offer.
917 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
918
919 EXPECT_TRUE_WAIT(
920 caller->pc()->local_description()->candidates(0)->count() > 0,
921 kIceCandidatesTimeout);
922
923 // Remove the only network interface, causing the PeerConnection to signal
924 // the removal of all candidates derived from this interface.
925 caller->network()->RemoveInterface(kLocalAddress);
926
927 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
928 kIceCandidatesTimeout);
929 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
930}
931
Steve Anton46d926a2018-01-23 10:23:06 -0800932TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700933 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
934 const SocketAddress kLocalAddress("1.1.1.1", 0);
935
936 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100937 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700938 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
939 auto caller = CreatePeerConnectionWithAudioVideo(config);
940 caller->network()->AddInterface(kLocalAddress);
941
942 // Start ICE candidate gathering by setting the local offer.
943 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
944
945 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
946
947 caller->network()->RemoveInterface(kLocalAddress);
948
949 // Verify that the local candidates are not removed;
950 rtc::Thread::Current()->ProcessMessages(1000);
951 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
952}
953
954// The following group tests that when an offer includes a new ufrag or pwd
955// (indicating an ICE restart) the old candidates are removed and new candidates
956// added to the remote description.
957
Steve Anton46d926a2018-01-23 10:23:06 -0800958TEST_P(PeerConnectionIceTest, IceRestartOfferClearsExistingCandidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700959 const SocketAddress kCallerAddress("1.1.1.1", 1111);
960
961 auto caller = CreatePeerConnectionWithAudioVideo();
962 auto callee = CreatePeerConnectionWithAudioVideo();
963
Amit Hilbuchae3df542019-01-07 12:13:08 -0800964 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700965 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
966 AddCandidateToFirstTransport(&candidate, offer.get());
967
968 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
969
970 RTCOfferAnswerOptions options;
971 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800972 ASSERT_TRUE(
973 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700974
975 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
976}
Steve Anton46d926a2018-01-23 10:23:06 -0800977TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700978 IceRestartOfferCandidateReplacesExistingCandidate) {
979 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
980 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
981
982 auto caller = CreatePeerConnectionWithAudioVideo();
983 auto callee = CreatePeerConnectionWithAudioVideo();
984
Amit Hilbuchae3df542019-01-07 12:13:08 -0800985 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700986 cricket::Candidate old_candidate =
987 CreateLocalUdpCandidate(kFirstCallerAddress);
988 AddCandidateToFirstTransport(&old_candidate, offer.get());
989
990 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
991
992 RTCOfferAnswerOptions options;
993 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800994 auto restart_offer = caller->CreateOfferAndSetAsLocal(options);
Steve Antonf1c6db12017-10-13 11:13:35 -0700995 cricket::Candidate new_candidate =
996 CreateLocalUdpCandidate(kRestartedCallerAddress);
997 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
998
999 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
1000
1001 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
1002 ASSERT_EQ(1u, remote_candidates.size());
1003 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
1004 remote_candidates[0]->candidate());
1005}
1006
1007// Test that if there is not an ICE restart (i.e., nothing changes), then the
1008// answer to a later offer should have the same ufrag/pwd as the first answer.
Steve Anton46d926a2018-01-23 10:23:06 -08001009TEST_P(PeerConnectionIceTest, LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
Steve Antonf1c6db12017-10-13 11:13:35 -07001010 auto caller = CreatePeerConnectionWithAudioVideo();
1011 auto callee = CreatePeerConnectionWithAudioVideo();
1012
1013 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1014 ASSERT_TRUE(
1015 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1016
1017 // Re-offer.
1018 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1019
1020 auto answer = callee->CreateAnswer();
1021 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
1022 auto* local_transport_desc =
1023 GetFirstTransportDescription(callee->pc()->local_description());
1024
1025 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
1026 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
1027}
1028
Henrik Boström79b69802019-07-18 11:16:56 +02001029TEST_P(PeerConnectionIceTest, RestartIceGeneratesNewCredentials) {
1030 auto caller = CreatePeerConnectionWithAudioVideo();
1031 auto callee = CreatePeerConnectionWithAudioVideo();
1032
1033 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1034 auto initial_ice_credentials =
1035 GetIceCredentials(caller->pc()->local_description());
1036 caller->pc()->RestartIce();
1037 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1038 auto restarted_ice_credentials =
1039 GetIceCredentials(caller->pc()->local_description());
1040 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1041}
1042
1043TEST_P(PeerConnectionIceTest,
1044 RestartIceWhileLocalOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1045 auto caller = CreatePeerConnectionWithAudioVideo();
1046 auto callee = CreatePeerConnectionWithAudioVideo();
1047
1048 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1049 auto initial_ice_credentials =
1050 GetIceCredentials(caller->pc()->local_description());
Artem Titov880fa812021-07-30 22:30:23 +02001051 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001052 // offerer.
1053 caller->pc()->RestartIce();
1054 ASSERT_TRUE(
1055 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1056 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1057 auto restarted_ice_credentials =
1058 GetIceCredentials(caller->pc()->local_description());
1059 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1060}
1061
1062TEST_P(PeerConnectionIceTest,
1063 RestartIceWhileRemoteOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1064 auto caller = CreatePeerConnectionWithAudioVideo();
1065 auto callee = CreatePeerConnectionWithAudioVideo();
1066
1067 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1068 auto initial_ice_credentials =
1069 GetIceCredentials(caller->pc()->local_description());
1070 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001071 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001072 // answerer.
1073 caller->pc()->RestartIce();
1074 ASSERT_TRUE(
1075 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
1076 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1077 auto restarted_ice_credentials =
1078 GetIceCredentials(caller->pc()->local_description());
1079 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1080}
1081
1082TEST_P(PeerConnectionIceTest, RestartIceTriggeredByRemoteSide) {
1083 auto caller = CreatePeerConnectionWithAudioVideo();
1084 auto callee = CreatePeerConnectionWithAudioVideo();
1085
1086 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1087 auto initial_ice_credentials =
1088 GetIceCredentials(caller->pc()->local_description());
1089
Artem Titov880fa812021-07-30 22:30:23 +02001090 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001091 // restart ICE locally as well.
1092 callee->pc()->RestartIce();
1093 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1094
1095 auto restarted_ice_credentials =
1096 GetIceCredentials(caller->pc()->local_description());
1097 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1098}
1099
1100TEST_P(PeerConnectionIceTest, RestartIceCausesNegotiationNeeded) {
1101 auto caller = CreatePeerConnectionWithAudioVideo();
1102 auto callee = CreatePeerConnectionWithAudioVideo();
1103
1104 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001105 caller->observer()->clear_legacy_renegotiation_needed();
1106 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001107 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001108 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1109 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001110}
1111
1112// In Unified Plan, "onnegotiationneeded" is spec-compliant, including not
1113// firing multipe times in a row, or firing when returning to the stable
1114// signaling state if negotiation is still needed. In Plan B it fires any time
1115// something changes. As such, some tests are SdpSemantics-specific.
1116class PeerConnectionIceTestUnifiedPlan : public PeerConnectionIceBaseTest {
1117 protected:
1118 PeerConnectionIceTestUnifiedPlan()
1119 : PeerConnectionIceBaseTest(SdpSemantics::kUnifiedPlan) {}
1120};
1121
1122TEST_F(PeerConnectionIceTestUnifiedPlan,
1123 RestartIceWhileLocalOfferIsPendingCausesNegotiationNeededWhenStable) {
1124 auto caller = CreatePeerConnectionWithAudioVideo();
1125 auto callee = CreatePeerConnectionWithAudioVideo();
1126
1127 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001128 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001129 // offerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001130 caller->observer()->clear_legacy_renegotiation_needed();
1131 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001132 caller->pc()->RestartIce();
1133 // In Unified Plan, the event should not fire until we are back in the stable
1134 // signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001135 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1136 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001137 ASSERT_TRUE(
1138 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001139 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1140 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001141}
1142
1143TEST_F(PeerConnectionIceTestUnifiedPlan,
1144 RestartIceWhileRemoteOfferIsPendingCausesNegotiationNeededWhenStable) {
1145 auto caller = CreatePeerConnectionWithAudioVideo();
1146 auto callee = CreatePeerConnectionWithAudioVideo();
1147
1148 // Establish initial credentials as the caller.
1149 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1150 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001151 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001152 // answerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001153 caller->observer()->clear_legacy_renegotiation_needed();
1154 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001155 caller->pc()->RestartIce();
1156 // In Unified Plan, the event should not fire until we are back in the stable
1157 // signaling state.
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 ASSERT_TRUE(
1161 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001162 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1163 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001164}
1165
1166TEST_F(PeerConnectionIceTestUnifiedPlan,
1167 RestartIceTriggeredByRemoteSideCauseNegotiationNotNeeded) {
1168 auto caller = CreatePeerConnectionWithAudioVideo();
1169 auto callee = CreatePeerConnectionWithAudioVideo();
1170
1171 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1172 // Local restart.
1173 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001174 caller->observer()->clear_legacy_renegotiation_needed();
1175 caller->observer()->clear_latest_negotiation_needed_event();
Artem Titov880fa812021-07-30 22:30:23 +02001176 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001177 // restart ICE locally as well.
1178 callee->pc()->RestartIce();
1179 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1180 // Having restarted ICE by the remote offer, we do not need to renegotiate ICE
1181 // credentials when back in the stable signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001182 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1183 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001184}
1185
1186TEST_F(PeerConnectionIceTestUnifiedPlan,
1187 RestartIceTwiceDoesNotFireNegotiationNeededTwice) {
1188 auto caller = CreatePeerConnectionWithAudioVideo();
1189 auto callee = CreatePeerConnectionWithAudioVideo();
1190
1191 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1192 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001193 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1194 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1195 caller->observer()->clear_legacy_renegotiation_needed();
1196 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001197 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001198 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1199 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001200}
1201
1202// In Plan B, "onnegotiationneeded" is not spec-compliant, firing based on if
1203// something changed rather than if negotiation is needed. In Unified Plan it
1204// fires according to spec. As such, some tests are SdpSemantics-specific.
1205class PeerConnectionIceTestPlanB : public PeerConnectionIceBaseTest {
1206 protected:
1207 PeerConnectionIceTestPlanB()
Florent Castelli15a38de2022-04-06 00:38:21 +02001208 : PeerConnectionIceBaseTest(SdpSemantics::kPlanB_DEPRECATED) {}
Henrik Boström79b69802019-07-18 11:16:56 +02001209};
1210
1211TEST_F(PeerConnectionIceTestPlanB,
1212 RestartIceWhileOfferIsPendingCausesNegotiationNeededImmediately) {
1213 auto caller = CreatePeerConnectionWithAudioVideo();
1214 auto callee = CreatePeerConnectionWithAudioVideo();
1215
1216 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001217 caller->observer()->clear_legacy_renegotiation_needed();
1218 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001219 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001220 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1221 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1222 caller->observer()->clear_legacy_renegotiation_needed();
1223 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001224 ASSERT_TRUE(
1225 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1226 // In Plan B, the event fired early so we don't expect it to fire now. This is
1227 // not spec-compliant but follows the pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001228 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1229 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001230}
1231
1232TEST_F(PeerConnectionIceTestPlanB,
1233 RestartIceTwiceDoesFireNegotiationNeededTwice) {
1234 auto caller = CreatePeerConnectionWithAudioVideo();
1235 auto callee = CreatePeerConnectionWithAudioVideo();
1236
1237 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001238 caller->observer()->clear_legacy_renegotiation_needed();
1239 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001240 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001241 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1242 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1243 caller->observer()->clear_legacy_renegotiation_needed();
1244 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001245 caller->pc()->RestartIce();
1246 // In Plan B, the event fires every time something changed, even if we have
1247 // already fired the event. This is not spec-compliant but follows the same
1248 // pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001249 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1250 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001251}
1252
Steve Antonf1c6db12017-10-13 11:13:35 -07001253// The following parameterized test verifies that if an offer is sent with a
1254// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
1255// other side has initiated an ICE restart and generate a new ufrag and pwd.
1256// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
1257// a=ice-pwd attributes compared to the previous SDP from the peer, it
1258// indicates that ICE is restarting for this media stream."
1259
Steve Anton46d926a2018-01-23 10:23:06 -08001260class PeerConnectionIceUfragPwdAnswerTest
1261 : public PeerConnectionIceBaseTest,
1262 public ::testing::WithParamInterface<
1263 std::tuple<SdpSemantics, std::tuple<bool, bool>>> {
Steve Antonf1c6db12017-10-13 11:13:35 -07001264 protected:
Steve Anton46d926a2018-01-23 10:23:06 -08001265 PeerConnectionIceUfragPwdAnswerTest()
1266 : PeerConnectionIceBaseTest(std::get<0>(GetParam())) {
1267 auto param = std::get<1>(GetParam());
1268 offer_new_ufrag_ = std::get<0>(param);
1269 offer_new_pwd_ = std::get<1>(param);
Steve Antonf1c6db12017-10-13 11:13:35 -07001270 }
1271
1272 bool offer_new_ufrag_;
1273 bool offer_new_pwd_;
1274};
1275
Steve Anton46d926a2018-01-23 10:23:06 -08001276TEST_P(PeerConnectionIceUfragPwdAnswerTest, TestIncludedInAnswer) {
Steve Antonf1c6db12017-10-13 11:13:35 -07001277 auto caller = CreatePeerConnectionWithAudioVideo();
1278 auto callee = CreatePeerConnectionWithAudioVideo();
1279
1280 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1281 ASSERT_TRUE(
1282 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1283
1284 auto offer = caller->CreateOffer();
1285 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
1286 if (offer_new_ufrag_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001287 offer_transport_desc->ice_ufrag += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001288 }
1289 if (offer_new_pwd_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001290 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001291 }
1292
1293 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1294
1295 auto answer = callee->CreateAnswer();
1296 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
1297 auto* local_transport_desc =
1298 GetFirstTransportDescription(callee->pc()->local_description());
1299
1300 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
1301 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
1302}
1303
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001304INSTANTIATE_TEST_SUITE_P(
Steve Anton46d926a2018-01-23 10:23:06 -08001305 PeerConnectionIceTest,
1306 PeerConnectionIceUfragPwdAnswerTest,
Florent Castelli15a38de2022-04-06 00:38:21 +02001307 Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Anton46d926a2018-01-23 10:23:06 -08001308 Values(std::make_pair(true, true), // Both changed.
1309 std::make_pair(true, false), // Only ufrag changed.
1310 std::make_pair(false, true)))); // Only pwd changed.
Steve Antonf1c6db12017-10-13 11:13:35 -07001311
1312// Test that if an ICE restart is offered on one media section, then the answer
1313// will only change ICE ufrag/pwd for that section and keep the other sections
1314// the same.
1315// Note that this only works if we have disabled BUNDLE, otherwise all media
1316// sections will share the same transport.
Steve Anton46d926a2018-01-23 10:23:06 -08001317TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -07001318 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
1319 auto caller = CreatePeerConnectionWithAudioVideo();
1320 auto callee = CreatePeerConnectionWithAudioVideo();
1321
1322 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1323 ASSERT_TRUE(
1324 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1325
1326 RTCOfferAnswerOptions disable_bundle_options;
1327 disable_bundle_options.use_rtp_mux = false;
1328
1329 auto offer = caller->CreateOffer(disable_bundle_options);
1330
1331 // Signal ICE restart on the first media section.
1332 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
Steve Anton71ff0732020-01-24 16:28:15 -08001333 offer_transport_desc->ice_ufrag += "+new";
1334 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001335
1336 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1337
1338 auto answer = callee->CreateAnswer(disable_bundle_options);
1339 const auto& answer_transports = answer->description()->transport_infos();
1340 const auto& local_transports =
1341 callee->pc()->local_description()->description()->transport_infos();
1342
1343 EXPECT_NE(answer_transports[0].description.ice_ufrag,
1344 local_transports[0].description.ice_ufrag);
1345 EXPECT_NE(answer_transports[0].description.ice_pwd,
1346 local_transports[0].description.ice_pwd);
1347 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
1348 local_transports[1].description.ice_ufrag);
1349 EXPECT_EQ(answer_transports[1].description.ice_pwd,
1350 local_transports[1].description.ice_pwd);
1351}
1352
Qingsi Wange1692722017-11-29 13:27:20 -08001353// Test that when the initial offerer (caller) uses the lite implementation of
1354// ICE and the callee uses the full implementation, the caller takes the
1355// CONTROLLED role and the callee takes the CONTROLLING role. This is specified
1356// in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001357TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001358 OfferFromLiteIceControlledAndAnswerFromFullIceControlling) {
1359 auto caller = CreatePeerConnectionWithAudioVideo();
1360 auto callee = CreatePeerConnectionWithAudioVideo();
1361
1362 auto offer = caller->CreateOffer();
1363 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1364 ASSERT_TRUE(
1365 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1366 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1367
1368 auto answer = callee->CreateAnswer();
1369 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_FULL);
1370 ASSERT_TRUE(
1371 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1372 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1373
1374 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(caller));
1375 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(callee));
1376}
1377
1378// Test that when the caller and the callee both use the lite implementation of
1379// ICE, the initial offerer (caller) takes the CONTROLLING role and the callee
1380// takes the CONTROLLED role. This is specified in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001381TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001382 OfferFromLiteIceControllingAndAnswerFromLiteIceControlled) {
1383 auto caller = CreatePeerConnectionWithAudioVideo();
1384 auto callee = CreatePeerConnectionWithAudioVideo();
1385
1386 auto offer = caller->CreateOffer();
1387 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1388 ASSERT_TRUE(
1389 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1390 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1391
1392 auto answer = callee->CreateAnswer();
1393 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_LITE);
1394 ASSERT_TRUE(
1395 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1396 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1397
1398 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(caller));
1399 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(callee));
1400}
1401
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001402INSTANTIATE_TEST_SUITE_P(PeerConnectionIceTest,
1403 PeerConnectionIceTest,
Florent Castelli15a38de2022-04-06 00:38:21 +02001404 Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001405 SdpSemantics::kUnifiedPlan));
Steve Anton46d926a2018-01-23 10:23:06 -08001406
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001407class PeerConnectionIceConfigTest : public ::testing::Test {
Qingsi Wang4ff54432018-03-01 18:25:20 -08001408 protected:
1409 void SetUp() override {
1410 pc_factory_ = CreatePeerConnectionFactory(
1411 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
1412 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
Anders Carlsson67537952018-05-03 11:28:29 +02001413 CreateBuiltinAudioDecoderFactory(), CreateBuiltinVideoEncoderFactory(),
1414 CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
1415 nullptr /* audio_processing */);
Qingsi Wang4ff54432018-03-01 18:25:20 -08001416 }
1417 void CreatePeerConnection(const RTCConfiguration& config) {
1418 std::unique_ptr<cricket::FakePortAllocator> port_allocator(
1419 new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr));
1420 port_allocator_ = port_allocator.get();
Florent Castelli72424402022-04-06 03:45:10 +02001421 PeerConnectionDependencies pc_dependencies(&observer_);
1422 pc_dependencies.allocator = std::move(port_allocator);
1423 auto result = pc_factory_->CreatePeerConnectionOrError(
1424 config, std::move(pc_dependencies));
1425 EXPECT_TRUE(result.ok());
1426 pc_ = result.MoveValue();
Qingsi Wang4ff54432018-03-01 18:25:20 -08001427 }
1428
Niels Möller83830f32022-05-20 09:12:57 +02001429 rtc::AutoThread main_thread_;
Qingsi Wang4ff54432018-03-01 18:25:20 -08001430 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_ = nullptr;
1431 rtc::scoped_refptr<PeerConnectionInterface> pc_ = nullptr;
1432 cricket::FakePortAllocator* port_allocator_ = nullptr;
1433
1434 MockPeerConnectionObserver observer_;
1435};
1436
1437TEST_F(PeerConnectionIceConfigTest, SetStunCandidateKeepaliveInterval) {
1438 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001439 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Qingsi Wang4ff54432018-03-01 18:25:20 -08001440 config.stun_candidate_keepalive_interval = 123;
1441 config.ice_candidate_pool_size = 1;
1442 CreatePeerConnection(config);
1443 ASSERT_NE(port_allocator_, nullptr);
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001444 absl::optional<int> actual_stun_keepalive_interval =
Qingsi Wang4ff54432018-03-01 18:25:20 -08001445 port_allocator_->stun_candidate_keepalive_interval();
1446 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 123);
1447 config.stun_candidate_keepalive_interval = 321;
Niels Möller2579f0c2019-08-19 09:58:17 +02001448 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
Qingsi Wang4ff54432018-03-01 18:25:20 -08001449 actual_stun_keepalive_interval =
1450 port_allocator_->stun_candidate_keepalive_interval();
1451 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 321);
1452}
1453
Derek Bailey6c127a12021-04-15 12:42:41 -07001454TEST_F(PeerConnectionIceConfigTest, SetStableWritableConnectionInterval) {
1455 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001456 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001457 config.stable_writable_connection_ping_interval_ms = 3500;
1458 CreatePeerConnection(config);
1459 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1460 EXPECT_EQ(pc_->GetConfiguration().stable_writable_connection_ping_interval_ms,
1461 config.stable_writable_connection_ping_interval_ms);
1462}
1463
1464TEST_F(PeerConnectionIceConfigTest,
1465 SetStableWritableConnectionInterval_FailsValidation) {
1466 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001467 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001468 CreatePeerConnection(config);
1469 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1470 config.stable_writable_connection_ping_interval_ms = 5000;
1471 config.ice_check_interval_strong_connectivity = 7500;
1472 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1473}
1474
1475TEST_F(PeerConnectionIceConfigTest,
1476 SetStableWritableConnectionInterval_DefaultValue_FailsValidation) {
1477 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001478 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001479 CreatePeerConnection(config);
1480 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1481 config.ice_check_interval_strong_connectivity = 2500;
1482 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1483 config.ice_check_interval_strong_connectivity = 2501;
1484 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1485}
1486
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001487TEST_P(PeerConnectionIceTest, IceCredentialsCreateOffer) {
1488 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001489 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001490 config.ice_candidate_pool_size = 1;
1491 auto pc = CreatePeerConnectionWithAudioVideo(config);
1492 ASSERT_NE(pc->port_allocator_, nullptr);
1493 auto offer = pc->CreateOffer();
1494 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1495 ASSERT_EQ(1u, credentials.size());
1496
1497 auto* desc = offer->description();
1498 for (const auto& content : desc->contents()) {
1499 auto* transport_info = desc->GetTransportInfoByName(content.name);
1500 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1501 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1502 }
1503}
1504
1505TEST_P(PeerConnectionIceTest, IceCredentialsCreateAnswer) {
1506 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001507 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001508 config.ice_candidate_pool_size = 1;
1509 auto pc = CreatePeerConnectionWithAudioVideo(config);
1510 ASSERT_NE(pc->port_allocator_, nullptr);
1511 auto offer = pc->CreateOffer();
1512 ASSERT_TRUE(pc->SetRemoteDescription(std::move(offer)));
1513 auto answer = pc->CreateAnswer();
1514
1515 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1516 ASSERT_EQ(1u, credentials.size());
1517
1518 auto* desc = answer->description();
1519 for (const auto& content : desc->contents()) {
1520 auto* transport_info = desc->GetTransportInfoByName(content.name);
1521 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1522 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1523 }
1524}
1525
Steve Antonec47b572020-01-24 14:53:37 -08001526// Regression test for https://bugs.chromium.org/p/webrtc/issues/detail?id=4728
1527TEST_P(PeerConnectionIceTest, CloseDoesNotTransitionGatheringStateToComplete) {
1528 auto pc = CreatePeerConnectionWithAudioVideo();
1529 pc->pc()->Close();
1530 EXPECT_FALSE(pc->IsIceGatheringDone());
1531 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
1532 pc->pc()->ice_gathering_state());
1533}
1534
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001535TEST_P(PeerConnectionIceTest, PrefersMidOverMLineIndex) {
1536 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
1537
1538 auto caller = CreatePeerConnectionWithAudioVideo();
1539 auto callee = CreatePeerConnectionWithAudioVideo();
1540
1541 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1542 ASSERT_TRUE(
1543 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1544
Artem Titovcfea2182021-08-10 01:22:31 +02001545 // `candidate.transport_name()` is empty.
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001546 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
1547 auto* audio_content = cricket::GetFirstAudioContent(
1548 caller->pc()->local_description()->description());
1549 std::unique_ptr<IceCandidateInterface> ice_candidate =
1550 CreateIceCandidate(audio_content->name, 65535, candidate);
1551 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
1552 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
1553}
1554
Steve Antonf1c6db12017-10-13 11:13:35 -07001555} // namespace webrtc