blob: 56768377b077d0e0506140a28b1ccfdc747b6438 [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();
Florent Castelli72424402022-04-06 03:45:10 +0200170 PeerConnectionDependencies pc_dependencies(observer.get());
171 pc_dependencies.allocator = std::move(port_allocator);
172 auto result = pc_factory_->CreatePeerConnectionOrError(
173 modified_config, std::move(pc_dependencies));
174 if (!result.ok()) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700175 return nullptr;
176 }
177
Niels Möllerafb246b2022-04-20 14:26:50 +0200178 observer->SetPeerConnectionInterface(result.value().get());
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200179 auto wrapper = std::make_unique<PeerConnectionWrapperForIceTest>(
Florent Castelli72424402022-04-06 03:45:10 +0200180 pc_factory_, result.MoveValue(), std::move(observer));
Steve Antonf1c6db12017-10-13 11:13:35 -0700181 wrapper->set_network(fake_network);
Jonas Oreland1cd39fa2018-10-11 07:47:12 +0200182 wrapper->port_allocator_ = port_allocator_copy;
Steve Antonf1c6db12017-10-13 11:13:35 -0700183 return wrapper;
184 }
185
186 // Accepts the same arguments as CreatePeerConnection and adds default audio
187 // and video tracks.
188 template <typename... Args>
189 WrapperPtr CreatePeerConnectionWithAudioVideo(Args&&... args) {
190 auto wrapper = CreatePeerConnection(std::forward<Args>(args)...);
191 if (!wrapper) {
192 return nullptr;
193 }
Steve Anton8d3444d2017-10-20 15:30:51 -0700194 wrapper->AddAudioTrack("a");
195 wrapper->AddVideoTrack("v");
Steve Antonf1c6db12017-10-13 11:13:35 -0700196 return wrapper;
197 }
198
199 cricket::Candidate CreateLocalUdpCandidate(
200 const rtc::SocketAddress& address) {
201 cricket::Candidate candidate;
202 candidate.set_component(cricket::ICE_CANDIDATE_COMPONENT_DEFAULT);
203 candidate.set_protocol(cricket::UDP_PROTOCOL_NAME);
204 candidate.set_address(address);
205 candidate.set_type(cricket::LOCAL_PORT_TYPE);
206 return candidate;
207 }
208
209 // Remove all ICE ufrag/pwd lines from the given session description.
210 void RemoveIceUfragPwd(SessionDescriptionInterface* sdesc) {
211 SetIceUfragPwd(sdesc, "", "");
212 }
213
214 // Sets all ICE ufrag/pwds on the given session description.
215 void SetIceUfragPwd(SessionDescriptionInterface* sdesc,
216 const std::string& ufrag,
217 const std::string& pwd) {
218 auto* desc = sdesc->description();
219 for (const auto& content : desc->contents()) {
220 auto* transport_info = desc->GetTransportInfoByName(content.name);
221 transport_info->description.ice_ufrag = ufrag;
222 transport_info->description.ice_pwd = pwd;
223 }
224 }
225
Qingsi Wange1692722017-11-29 13:27:20 -0800226 // Set ICE mode on the given session description.
227 void SetIceMode(SessionDescriptionInterface* sdesc,
228 const cricket::IceMode ice_mode) {
229 auto* desc = sdesc->description();
230 for (const auto& content : desc->contents()) {
231 auto* transport_info = desc->GetTransportInfoByName(content.name);
232 transport_info->description.ice_mode = ice_mode;
233 }
234 }
235
Steve Antonf1c6db12017-10-13 11:13:35 -0700236 cricket::TransportDescription* GetFirstTransportDescription(
237 SessionDescriptionInterface* sdesc) {
238 auto* desc = sdesc->description();
239 RTC_DCHECK(desc->contents().size() > 0);
240 auto* transport_info =
241 desc->GetTransportInfoByName(desc->contents()[0].name);
242 RTC_DCHECK(transport_info);
243 return &transport_info->description;
244 }
245
246 const cricket::TransportDescription* GetFirstTransportDescription(
247 const SessionDescriptionInterface* sdesc) {
248 auto* desc = sdesc->description();
249 RTC_DCHECK(desc->contents().size() > 0);
250 auto* transport_info =
251 desc->GetTransportInfoByName(desc->contents()[0].name);
252 RTC_DCHECK(transport_info);
253 return &transport_info->description;
254 }
255
Qingsi Wange1692722017-11-29 13:27:20 -0800256 // TODO(qingsi): Rewrite this method in terms of the standard IceTransport
257 // after it is implemented.
258 cricket::IceRole GetIceRole(const WrapperPtr& pc_wrapper_ptr) {
Mirko Bonadeie97de912017-12-13 11:29:34 +0100259 auto* pc_proxy =
260 static_cast<PeerConnectionProxyWithInternal<PeerConnectionInterface>*>(
261 pc_wrapper_ptr->pc());
262 PeerConnection* pc = static_cast<PeerConnection*>(pc_proxy->internal());
Mirko Bonadei739baf02019-01-27 17:29:42 +0100263 for (const auto& transceiver : pc->GetTransceiversInternal()) {
Steve Anton69470252018-02-09 11:43:08 -0800264 if (transceiver->media_type() == cricket::MEDIA_TYPE_AUDIO) {
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700265 auto dtls_transport = pc->LookupDtlsTransportByMidInternal(
Tomas Gunnarsson5411b172022-01-24 08:45:26 +0100266 transceiver->internal()->channel()->mid());
Bjorn A Mellem3a1b9272019-05-24 16:13:08 -0700267 return dtls_transport->ice_transport()->internal()->GetIceRole();
Steve Anton46d926a2018-01-23 10:23:06 -0800268 }
269 }
Artem Titovd3251962021-11-15 16:57:07 +0100270 RTC_DCHECK_NOTREACHED();
Steve Anton46d926a2018-01-23 10:23:06 -0800271 return cricket::ICEROLE_UNKNOWN;
Qingsi Wange1692722017-11-29 13:27:20 -0800272 }
273
Henrik Boström79b69802019-07-18 11:16:56 +0200274 // Returns a list of (ufrag, pwd) pairs in the order that they appear in
Artem Titov880fa812021-07-30 22:30:23 +0200275 // `description`, or the empty list if `description` is null.
Henrik Boström79b69802019-07-18 11:16:56 +0200276 std::vector<std::pair<std::string, std::string>> GetIceCredentials(
277 const SessionDescriptionInterface* description) {
278 std::vector<std::pair<std::string, std::string>> ice_credentials;
279 if (!description)
280 return ice_credentials;
281 const auto* desc = description->description();
282 for (const auto& content_info : desc->contents()) {
283 const auto* transport_info =
284 desc->GetTransportInfoByName(content_info.name);
285 if (transport_info) {
286 ice_credentials.push_back(
287 std::make_pair(transport_info->description.ice_ufrag,
288 transport_info->description.ice_pwd));
289 }
290 }
291 return ice_credentials;
292 }
293
Steve Antonf1c6db12017-10-13 11:13:35 -0700294 bool AddCandidateToFirstTransport(cricket::Candidate* candidate,
295 SessionDescriptionInterface* sdesc) {
296 auto* desc = sdesc->description();
297 RTC_DCHECK(desc->contents().size() > 0);
298 const auto& first_content = desc->contents()[0];
299 candidate->set_transport_name(first_content.name);
Steve Anton27ab0e52018-07-23 15:11:53 -0700300 std::unique_ptr<IceCandidateInterface> jsep_candidate =
301 CreateIceCandidate(first_content.name, 0, *candidate);
302 return sdesc->AddCandidate(jsep_candidate.get());
Steve Antonf1c6db12017-10-13 11:13:35 -0700303 }
304
305 rtc::FakeNetworkManager* NewFakeNetwork() {
306 // The PeerConnection's port allocator is tied to the PeerConnection's
307 // lifetime and expects the underlying NetworkManager to outlive it. That
308 // prevents us from having the PeerConnectionWrapper own the fake network.
309 // Therefore, the test fixture will own all the fake networks even though
310 // tests should access the fake network through the PeerConnectionWrapper.
311 auto* fake_network = new rtc::FakeNetworkManager();
312 fake_networks_.emplace_back(fake_network);
313 return fake_network;
314 }
315
316 std::unique_ptr<rtc::VirtualSocketServer> vss_;
317 rtc::AutoSocketServerThread main_;
318 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_;
319 std::vector<std::unique_ptr<rtc::FakeNetworkManager>> fake_networks_;
Steve Anton46d926a2018-01-23 10:23:06 -0800320 const SdpSemantics sdp_semantics_;
321};
322
323class PeerConnectionIceTest
324 : public PeerConnectionIceBaseTest,
325 public ::testing::WithParamInterface<SdpSemantics> {
326 protected:
Harald Alvestrand76829d72018-07-18 23:24:36 +0200327 PeerConnectionIceTest() : PeerConnectionIceBaseTest(GetParam()) {
328 webrtc::metrics::Reset();
329 }
Steve Antonf1c6db12017-10-13 11:13:35 -0700330};
331
332::testing::AssertionResult AssertCandidatesEqual(const char* a_expr,
333 const char* b_expr,
334 const cricket::Candidate& a,
335 const cricket::Candidate& b) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200336 rtc::StringBuilder failure_info;
Steve Antonf1c6db12017-10-13 11:13:35 -0700337 if (a.component() != b.component()) {
338 failure_info << "\ncomponent: " << a.component() << " != " << b.component();
339 }
340 if (a.protocol() != b.protocol()) {
341 failure_info << "\nprotocol: " << a.protocol() << " != " << b.protocol();
342 }
343 if (a.address() != b.address()) {
344 failure_info << "\naddress: " << a.address().ToString()
345 << " != " << b.address().ToString();
346 }
347 if (a.type() != b.type()) {
348 failure_info << "\ntype: " << a.type() << " != " << b.type();
349 }
350 std::string failure_info_str = failure_info.str();
351 if (failure_info_str.empty()) {
352 return ::testing::AssertionSuccess();
353 } else {
354 return ::testing::AssertionFailure()
355 << a_expr << " and " << b_expr << " are not equal"
356 << failure_info_str;
357 }
358}
359
Steve Anton46d926a2018-01-23 10:23:06 -0800360TEST_P(PeerConnectionIceTest, OfferContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700361 const SocketAddress kLocalAddress("1.1.1.1", 0);
362
363 auto caller = CreatePeerConnectionWithAudioVideo();
364 caller->network()->AddInterface(kLocalAddress);
365
366 // Start ICE candidate gathering by setting the local offer.
367 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
368
369 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
370
371 auto offer = caller->CreateOffer();
372 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
373 EXPECT_EQ(caller->observer()->GetCandidatesByMline(0).size(),
374 offer->candidates(0)->count());
375 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
376 EXPECT_EQ(caller->observer()->GetCandidatesByMline(1).size(),
377 offer->candidates(1)->count());
378}
379
Steve Anton46d926a2018-01-23 10:23:06 -0800380TEST_P(PeerConnectionIceTest, AnswerContainsGatheredCandidates) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700381 const SocketAddress kCallerAddress("1.1.1.1", 0);
382
383 auto caller = CreatePeerConnectionWithAudioVideo();
384 auto callee = CreatePeerConnectionWithAudioVideo();
385 caller->network()->AddInterface(kCallerAddress);
386
387 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
388 ASSERT_TRUE(callee->SetLocalDescription(callee->CreateAnswer()));
389
390 EXPECT_TRUE_WAIT(callee->IsIceGatheringDone(), kIceCandidatesTimeout);
391
Steve Antondffead82018-02-06 10:31:29 -0800392 auto* answer = callee->pc()->local_description();
Steve Antonf1c6db12017-10-13 11:13:35 -0700393 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(0).size());
394 EXPECT_EQ(callee->observer()->GetCandidatesByMline(0).size(),
395 answer->candidates(0)->count());
396 EXPECT_LT(0u, caller->observer()->GetCandidatesByMline(1).size());
397 EXPECT_EQ(callee->observer()->GetCandidatesByMline(1).size(),
398 answer->candidates(1)->count());
399}
400
Steve Anton46d926a2018-01-23 10:23:06 -0800401TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700402 CanSetRemoteSessionDescriptionWithRemoteCandidates) {
403 const SocketAddress kCallerAddress("1.1.1.1", 1111);
404
405 auto caller = CreatePeerConnectionWithAudioVideo();
406 auto callee = CreatePeerConnectionWithAudioVideo();
407
408 auto offer = caller->CreateOfferAndSetAsLocal();
409 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
410 AddCandidateToFirstTransport(&candidate, offer.get());
411
412 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
413 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
414 ASSERT_EQ(1u, remote_candidates.size());
415 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
416 remote_candidates[0]->candidate());
417}
418
Steve Anton46d926a2018-01-23 10:23:06 -0800419TEST_P(PeerConnectionIceTest, SetLocalDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700420 auto caller = CreatePeerConnectionWithAudioVideo();
421
422 auto offer = caller->CreateOffer();
423 RemoveIceUfragPwd(offer.get());
424
425 EXPECT_FALSE(caller->SetLocalDescription(std::move(offer)));
426}
427
Steve Anton46d926a2018-01-23 10:23:06 -0800428TEST_P(PeerConnectionIceTest, SetRemoteDescriptionFailsIfNoIceCredentials) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700429 auto caller = CreatePeerConnectionWithAudioVideo();
430 auto callee = CreatePeerConnectionWithAudioVideo();
431
432 auto offer = caller->CreateOfferAndSetAsLocal();
433 RemoveIceUfragPwd(offer.get());
434
435 EXPECT_FALSE(callee->SetRemoteDescription(std::move(offer)));
436}
437
Steve Antonf764cf42018-05-01 14:32:17 -0700438// Test that doing an offer/answer exchange with no transport (i.e., no data
439// channel or media) results in the ICE connection state staying at New.
440TEST_P(PeerConnectionIceTest,
441 OfferAnswerWithNoTransportsDoesNotChangeIceConnectionState) {
442 auto caller = CreatePeerConnection();
443 auto callee = CreatePeerConnection();
444
445 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
446
447 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
448 caller->pc()->ice_connection_state());
449 EXPECT_EQ(PeerConnectionInterface::kIceConnectionNew,
450 callee->pc()->ice_connection_state());
451}
452
Steve Antonf1c6db12017-10-13 11:13:35 -0700453// The following group tests that ICE candidates are not generated before
454// SetLocalDescription is called on a PeerConnection.
455
Steve Anton46d926a2018-01-23 10:23:06 -0800456TEST_P(PeerConnectionIceTest, NoIceCandidatesBeforeSetLocalDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700457 const SocketAddress kLocalAddress("1.1.1.1", 0);
458
459 auto caller = CreatePeerConnectionWithAudioVideo();
460 caller->network()->AddInterface(kLocalAddress);
461
462 // Pump for 1 second and verify that no candidates are generated.
463 rtc::Thread::Current()->ProcessMessages(1000);
464
465 EXPECT_EQ(0u, caller->observer()->candidates_.size());
466}
Steve Anton46d926a2018-01-23 10:23:06 -0800467TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700468 NoIceCandidatesBeforeAnswerSetAsLocalDescription) {
469 const SocketAddress kCallerAddress("1.1.1.1", 1111);
470
471 auto caller = CreatePeerConnectionWithAudioVideo();
472 auto callee = CreatePeerConnectionWithAudioVideo();
473 caller->network()->AddInterface(kCallerAddress);
474
475 auto offer = caller->CreateOfferAndSetAsLocal();
476 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
477 AddCandidateToFirstTransport(&candidate, offer.get());
478 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
479
480 // Pump for 1 second and verify that no candidates are generated.
481 rtc::Thread::Current()->ProcessMessages(1000);
482
483 EXPECT_EQ(0u, callee->observer()->candidates_.size());
484}
485
Steve Anton46d926a2018-01-23 10:23:06 -0800486TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenRemoteDescriptionNotSet) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700487 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
488
489 auto caller = CreatePeerConnectionWithAudioVideo();
490 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton27ab0e52018-07-23 15:11:53 -0700491 std::unique_ptr<IceCandidateInterface> jsep_candidate =
492 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
Steve Antonf1c6db12017-10-13 11:13:35 -0700493
Steve Anton27ab0e52018-07-23 15:11:53 -0700494 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700495
496 caller->CreateOfferAndSetAsLocal();
497
Steve Anton27ab0e52018-07-23 15:11:53 -0700498 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Ying Wangef3998f2019-12-09 13:06:53 +0100499 EXPECT_METRIC_THAT(
500 webrtc::metrics::Samples("WebRTC.PeerConnection.AddIceCandidate"),
501 ElementsAre(Pair(kAddIceCandidateFailNoRemoteDescription, 2)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700502}
503
Steve Antonc79268f2018-04-24 09:54:10 -0700504TEST_P(PeerConnectionIceTest, CannotAddCandidateWhenPeerConnectionClosed) {
505 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
506
507 auto caller = CreatePeerConnectionWithAudioVideo();
508 auto callee = CreatePeerConnectionWithAudioVideo();
509
510 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
511
512 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
513 auto* audio_content = cricket::GetFirstAudioContent(
514 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700515 std::unique_ptr<IceCandidateInterface> jsep_candidate =
516 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700517
518 caller->pc()->Close();
519
Steve Anton27ab0e52018-07-23 15:11:53 -0700520 EXPECT_FALSE(caller->pc()->AddIceCandidate(jsep_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700521}
522
Steve Anton46d926a2018-01-23 10:23:06 -0800523TEST_P(PeerConnectionIceTest, DuplicateIceCandidateIgnoredWhenAdded) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700524 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
525
526 auto caller = CreatePeerConnectionWithAudioVideo();
527 auto callee = CreatePeerConnectionWithAudioVideo();
528
529 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
530 ASSERT_TRUE(
531 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
532
533 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
534 caller->AddIceCandidate(&candidate);
535 EXPECT_TRUE(caller->AddIceCandidate(&candidate));
536 EXPECT_EQ(1u, caller->GetIceCandidatesFromRemoteDescription().size());
537}
538
Tomas Gunnarsson27bc6e22021-02-12 13:16:26 +0100539// TODO(tommi): Re-enable after updating RTCPeerConnection-blockedPorts.html in
540// Chromium (the test needs setRemoteDescription to succeed for an invalid
541// candidate).
542TEST_P(PeerConnectionIceTest, DISABLED_ErrorOnInvalidRemoteIceCandidateAdded) {
Tomas Gunnarsson8cb97062021-02-08 18:57:04 +0100543 auto caller = CreatePeerConnectionWithAudioVideo();
544 auto callee = CreatePeerConnectionWithAudioVideo();
545 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
546 // Add a candidate to the remote description with a candidate that has an
547 // invalid address (port number == 2).
548 auto answer = callee->CreateAnswerAndSetAsLocal();
549 cricket::Candidate bad_candidate =
550 CreateLocalUdpCandidate(SocketAddress("2.2.2.2", 2));
551 RTC_LOG(LS_INFO) << "Bad candidate: " << bad_candidate.ToString();
552 AddCandidateToFirstTransport(&bad_candidate, answer.get());
553 // Now the call to SetRemoteDescription should fail.
554 EXPECT_FALSE(caller->SetRemoteDescription(std::move(answer)));
555}
556
Steve Anton46d926a2018-01-23 10:23:06 -0800557TEST_P(PeerConnectionIceTest,
Steve Antonc79268f2018-04-24 09:54:10 -0700558 CannotRemoveIceCandidatesWhenPeerConnectionClosed) {
559 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
560
561 auto caller = CreatePeerConnectionWithAudioVideo();
562 auto callee = CreatePeerConnectionWithAudioVideo();
563
564 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
565
566 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
567 auto* audio_content = cricket::GetFirstAudioContent(
568 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700569 std::unique_ptr<IceCandidateInterface> ice_candidate =
570 CreateIceCandidate(audio_content->name, 0, candidate);
Steve Antonc79268f2018-04-24 09:54:10 -0700571
Steve Anton27ab0e52018-07-23 15:11:53 -0700572 ASSERT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonc79268f2018-04-24 09:54:10 -0700573
574 caller->pc()->Close();
575
576 EXPECT_FALSE(caller->pc()->RemoveIceCandidates({candidate}));
577}
578
579TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700580 AddRemoveCandidateWithEmptyTransportDoesNotCrash) {
581 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
582
583 auto caller = CreatePeerConnectionWithAudioVideo();
584 auto callee = CreatePeerConnectionWithAudioVideo();
585
586 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
587 ASSERT_TRUE(
588 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
589
Artem Titovcfea2182021-08-10 01:22:31 +0200590 // `candidate.transport_name()` is empty.
Steve Antonf1c6db12017-10-13 11:13:35 -0700591 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
Steve Anton46d926a2018-01-23 10:23:06 -0800592 auto* audio_content = cricket::GetFirstAudioContent(
593 caller->pc()->local_description()->description());
Steve Anton27ab0e52018-07-23 15:11:53 -0700594 std::unique_ptr<IceCandidateInterface> ice_candidate =
595 CreateIceCandidate(audio_content->name, 0, candidate);
596 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
Steve Antonf1c6db12017-10-13 11:13:35 -0700597 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
598}
599
Steve Anton46d926a2018-01-23 10:23:06 -0800600TEST_P(PeerConnectionIceTest, RemoveCandidateRemovesFromRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700601 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
602
603 auto caller = CreatePeerConnectionWithAudioVideo();
604 auto callee = CreatePeerConnectionWithAudioVideo();
605
606 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
607 ASSERT_TRUE(
608 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
609
610 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
611 ASSERT_TRUE(caller->AddIceCandidate(&candidate));
612 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
613 EXPECT_EQ(0u, caller->GetIceCandidatesFromRemoteDescription().size());
614}
615
616// Test that if a candidate is added via AddIceCandidate and via an updated
617// remote description, then both candidates appear in the stored remote
618// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800619TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700620 CandidateInSubsequentOfferIsAddedToRemoteDescription) {
621 const SocketAddress kCallerAddress1("1.1.1.1", 1111);
622 const SocketAddress kCallerAddress2("2.2.2.2", 2222);
623
624 auto caller = CreatePeerConnectionWithAudioVideo();
625 auto callee = CreatePeerConnectionWithAudioVideo();
626
627 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
628 ASSERT_TRUE(
629 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
630
Artem Titov880fa812021-07-30 22:30:23 +0200631 // Add one candidate via `AddIceCandidate`.
Steve Antonf1c6db12017-10-13 11:13:35 -0700632 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCallerAddress1);
633 ASSERT_TRUE(callee->AddIceCandidate(&candidate1));
634
635 // Add the second candidate via a reoffer.
636 auto offer = caller->CreateOffer();
637 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCallerAddress2);
638 AddCandidateToFirstTransport(&candidate2, offer.get());
639
640 // Expect both candidates to appear in the callee's remote description.
641 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
642 EXPECT_EQ(2u, callee->GetIceCandidatesFromRemoteDescription().size());
643}
644
645// The follow test verifies that SetLocal/RemoteDescription fails when an offer
646// has either ICE ufrag/pwd too short or too long and succeeds otherwise.
647// The standard (https://tools.ietf.org/html/rfc5245#section-15.4) says that
648// pwd must be 22-256 characters and ufrag must be 4-256 characters.
Steve Anton46d926a2018-01-23 10:23:06 -0800649TEST_P(PeerConnectionIceTest, VerifyUfragPwdLength) {
Yves Gerey665174f2018-06-19 15:03:05 +0200650 auto set_local_description_with_ufrag_pwd_length = [this](int ufrag_len,
651 int pwd_len) {
652 auto pc = CreatePeerConnectionWithAudioVideo();
653 auto offer = pc->CreateOffer();
654 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
655 std::string(pwd_len, 'x'));
656 return pc->SetLocalDescription(std::move(offer));
657 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700658
Yves Gerey665174f2018-06-19 15:03:05 +0200659 auto set_remote_description_with_ufrag_pwd_length = [this](int ufrag_len,
660 int pwd_len) {
661 auto pc = CreatePeerConnectionWithAudioVideo();
662 auto offer = pc->CreateOffer();
663 SetIceUfragPwd(offer.get(), std::string(ufrag_len, 'x'),
664 std::string(pwd_len, 'x'));
665 return pc->SetRemoteDescription(std::move(offer));
666 };
Steve Antonf1c6db12017-10-13 11:13:35 -0700667
668 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(3, 22));
669 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(3, 22));
670 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(257, 22));
671 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(257, 22));
672 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 21));
673 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 21));
674 EXPECT_FALSE(set_local_description_with_ufrag_pwd_length(4, 257));
675 EXPECT_FALSE(set_remote_description_with_ufrag_pwd_length(4, 257));
676 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(4, 22));
677 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(4, 22));
678 EXPECT_TRUE(set_local_description_with_ufrag_pwd_length(256, 256));
679 EXPECT_TRUE(set_remote_description_with_ufrag_pwd_length(256, 256));
680}
681
682::testing::AssertionResult AssertIpInCandidates(
683 const char* address_expr,
684 const char* candidates_expr,
685 const SocketAddress& address,
686 const std::vector<IceCandidateInterface*> candidates) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200687 rtc::StringBuilder candidate_hosts;
Steve Antonf1c6db12017-10-13 11:13:35 -0700688 for (const auto* candidate : candidates) {
689 const auto& candidate_ip = candidate->candidate().address().ipaddr();
690 if (candidate_ip == address.ipaddr()) {
691 return ::testing::AssertionSuccess();
692 }
Jonas Olssonabbe8412018-04-03 13:40:05 +0200693 candidate_hosts << "\n" << candidate_ip.ToString();
Steve Antonf1c6db12017-10-13 11:13:35 -0700694 }
695 return ::testing::AssertionFailure()
696 << address_expr << " (host " << address.HostAsURIString()
697 << ") not in " << candidates_expr
698 << " which have the following address hosts:" << candidate_hosts.str();
699}
700
Steve Anton46d926a2018-01-23 10:23:06 -0800701TEST_P(PeerConnectionIceTest, CandidatesGeneratedForEachLocalInterface) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700702 const SocketAddress kLocalAddress1("1.1.1.1", 0);
703 const SocketAddress kLocalAddress2("2.2.2.2", 0);
704
705 auto caller = CreatePeerConnectionWithAudioVideo();
706 caller->network()->AddInterface(kLocalAddress1);
707 caller->network()->AddInterface(kLocalAddress2);
708
709 caller->CreateOfferAndSetAsLocal();
710 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
711
712 auto candidates = caller->observer()->GetCandidatesByMline(0);
713 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress1, candidates);
714 EXPECT_PRED_FORMAT2(AssertIpInCandidates, kLocalAddress2, candidates);
715}
716
Steve Anton46d926a2018-01-23 10:23:06 -0800717TEST_P(PeerConnectionIceTest, TrickledSingleCandidateAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700718 const SocketAddress kCallerAddress("1.1.1.1", 1111);
719
720 auto caller = CreatePeerConnectionWithAudioVideo();
721 auto callee = CreatePeerConnectionWithAudioVideo();
722
723 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
724
725 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
726 callee->AddIceCandidate(&candidate);
727 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
728 ASSERT_EQ(1u, candidates.size());
729 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
730 candidates[0]->candidate());
731}
732
Steve Anton46d926a2018-01-23 10:23:06 -0800733TEST_P(PeerConnectionIceTest, TwoTrickledCandidatesAddedToRemoteDescription) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700734 const SocketAddress kCalleeAddress1("1.1.1.1", 1111);
735 const SocketAddress kCalleeAddress2("2.2.2.2", 2222);
736
737 auto caller = CreatePeerConnectionWithAudioVideo();
738 auto callee = CreatePeerConnectionWithAudioVideo();
739
740 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
741 ASSERT_TRUE(
742 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
743
744 cricket::Candidate candidate1 = CreateLocalUdpCandidate(kCalleeAddress1);
745 caller->AddIceCandidate(&candidate1);
746
747 cricket::Candidate candidate2 = CreateLocalUdpCandidate(kCalleeAddress2);
748 caller->AddIceCandidate(&candidate2);
749
750 auto candidates = caller->GetIceCandidatesFromRemoteDescription();
751 ASSERT_EQ(2u, candidates.size());
752 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate1,
753 candidates[0]->candidate());
754 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate2,
755 candidates[1]->candidate());
756}
757
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100758TEST_P(PeerConnectionIceTest, AsyncAddIceCandidateIsAddedToRemoteDescription) {
759 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
760
761 auto caller = CreatePeerConnectionWithAudioVideo();
762 auto callee = CreatePeerConnectionWithAudioVideo();
763
764 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
765
766 auto jsep_candidate =
767 callee->CreateJsepCandidateForFirstTransport(&candidate);
768 bool operation_completed = false;
769 callee->pc()->AddIceCandidate(std::move(jsep_candidate),
770 [&operation_completed](RTCError result) {
771 EXPECT_TRUE(result.ok());
772 operation_completed = true;
773 });
774 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
775
776 auto candidates = callee->GetIceCandidatesFromRemoteDescription();
777 ASSERT_EQ(1u, candidates.size());
778 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, candidate,
779 candidates[0]->candidate());
780}
781
782TEST_P(PeerConnectionIceTest,
783 AsyncAddIceCandidateCompletesImmediatelyIfNoPendingOperation) {
784 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
785
786 auto caller = CreatePeerConnectionWithAudioVideo();
787 auto callee = CreatePeerConnectionWithAudioVideo();
788
789 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
790
791 auto jsep_candidate =
792 callee->CreateJsepCandidateForFirstTransport(&candidate);
793 bool operation_completed = false;
794 callee->pc()->AddIceCandidate(
795 std::move(jsep_candidate),
796 [&operation_completed](RTCError result) { operation_completed = true; });
797 EXPECT_TRUE(operation_completed);
798}
799
800TEST_P(PeerConnectionIceTest,
801 AsyncAddIceCandidateCompletesWhenPendingOperationCompletes) {
802 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
803
804 auto caller = CreatePeerConnectionWithAudioVideo();
805 auto callee = CreatePeerConnectionWithAudioVideo();
806
807 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
808
809 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200810 auto answer_observer =
811 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Niels Möllerafb246b2022-04-20 14:26:50 +0200812 callee->pc()->CreateAnswer(answer_observer.get(), RTCOfferAnswerOptions());
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100813
814 auto jsep_candidate =
815 callee->CreateJsepCandidateForFirstTransport(&candidate);
816 bool operation_completed = false;
817 callee->pc()->AddIceCandidate(
818 std::move(jsep_candidate),
819 [&operation_completed](RTCError result) { operation_completed = true; });
820 // The operation will not be able to complete until we EXPECT_TRUE_WAIT()
821 // allowing CreateAnswer() to complete.
822 EXPECT_FALSE(operation_completed);
823 EXPECT_TRUE_WAIT(answer_observer->called(), kWaitTimeout);
824 // As soon as it does, AddIceCandidate() will execute without delay, so it
825 // must also have completed.
826 EXPECT_TRUE(operation_completed);
827}
828
829TEST_P(PeerConnectionIceTest,
830 AsyncAddIceCandidateFailsBeforeSetRemoteDescription) {
831 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
832
833 auto caller = CreatePeerConnectionWithAudioVideo();
834 std::unique_ptr<IceCandidateInterface> jsep_candidate =
835 CreateIceCandidate(cricket::CN_AUDIO, 0, candidate);
836
837 bool operation_completed = false;
838 caller->pc()->AddIceCandidate(
839 std::move(jsep_candidate), [&operation_completed](RTCError result) {
840 EXPECT_FALSE(result.ok());
841 EXPECT_EQ(result.message(),
Henrik Boström347488e2022-01-21 15:18:08 +0100842 std::string("The remote description was null"));
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100843 operation_completed = true;
844 });
845 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
846}
847
848TEST_P(PeerConnectionIceTest,
849 AsyncAddIceCandidateFailsIfPeerConnectionDestroyed) {
850 auto candidate = CreateLocalUdpCandidate(SocketAddress("1.1.1.1", 1111));
851
852 auto caller = CreatePeerConnectionWithAudioVideo();
853 auto callee = CreatePeerConnectionWithAudioVideo();
854
855 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
856
857 // Chain an operation that will block AddIceCandidate() from executing.
Tommi87f70902021-04-27 14:43:08 +0200858 auto answer_observer =
859 rtc::make_ref_counted<MockCreateSessionDescriptionObserver>();
Niels Möllerafb246b2022-04-20 14:26:50 +0200860 callee->pc()->CreateAnswer(answer_observer.get(), RTCOfferAnswerOptions());
Henrik Boströmee6f4f62019-11-06 12:36:12 +0100861
862 auto jsep_candidate =
863 callee->CreateJsepCandidateForFirstTransport(&candidate);
864 bool operation_completed = false;
865 callee->pc()->AddIceCandidate(
866 std::move(jsep_candidate), [&operation_completed](RTCError result) {
867 EXPECT_FALSE(result.ok());
868 EXPECT_EQ(
869 result.message(),
870 std::string(
871 "AddIceCandidate failed because the session was shut down"));
872 operation_completed = true;
873 });
874 // The operation will not be able to run until EXPECT_TRUE_WAIT(), giving us
875 // time to remove all references to the PeerConnection.
876 EXPECT_FALSE(operation_completed);
877 // This should delete the callee PC.
878 callee = nullptr;
879 EXPECT_TRUE_WAIT(operation_completed, kWaitTimeout);
880}
881
Steve Anton46d926a2018-01-23 10:23:06 -0800882TEST_P(PeerConnectionIceTest, LocalDescriptionUpdatedWhenContinualGathering) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700883 const SocketAddress kLocalAddress("1.1.1.1", 0);
884
885 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100886 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700887 config.continual_gathering_policy =
888 PeerConnectionInterface::GATHER_CONTINUALLY;
889 auto caller = CreatePeerConnectionWithAudioVideo(config);
890 caller->network()->AddInterface(kLocalAddress);
891
892 // Start ICE candidate gathering by setting the local offer.
893 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
894
895 // Since we're using continual gathering, we won't get "gathering done".
896 EXPECT_TRUE_WAIT(
897 caller->pc()->local_description()->candidates(0)->count() > 0,
898 kIceCandidatesTimeout);
899}
900
901// Test that when continual gathering is enabled, and a network interface goes
902// down, the candidate is signaled as removed and removed from the local
903// description.
Steve Anton46d926a2018-01-23 10:23:06 -0800904TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700905 LocalCandidatesRemovedWhenNetworkDownIfGatheringContinually) {
906 const SocketAddress kLocalAddress("1.1.1.1", 0);
907
908 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100909 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700910 config.continual_gathering_policy =
911 PeerConnectionInterface::GATHER_CONTINUALLY;
912 auto caller = CreatePeerConnectionWithAudioVideo(config);
913 caller->network()->AddInterface(kLocalAddress);
914
915 // Start ICE candidate gathering by setting the local offer.
916 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
917
918 EXPECT_TRUE_WAIT(
919 caller->pc()->local_description()->candidates(0)->count() > 0,
920 kIceCandidatesTimeout);
921
922 // Remove the only network interface, causing the PeerConnection to signal
923 // the removal of all candidates derived from this interface.
924 caller->network()->RemoveInterface(kLocalAddress);
925
926 EXPECT_EQ_WAIT(0u, caller->pc()->local_description()->candidates(0)->count(),
927 kIceCandidatesTimeout);
928 EXPECT_LT(0, caller->observer()->num_candidates_removed_);
929}
930
Steve Anton46d926a2018-01-23 10:23:06 -0800931TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700932 LocalCandidatesNotRemovedWhenNetworkDownIfGatheringOnce) {
933 const SocketAddress kLocalAddress("1.1.1.1", 0);
934
935 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +0100936 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Steve Antonf1c6db12017-10-13 11:13:35 -0700937 config.continual_gathering_policy = PeerConnectionInterface::GATHER_ONCE;
938 auto caller = CreatePeerConnectionWithAudioVideo(config);
939 caller->network()->AddInterface(kLocalAddress);
940
941 // Start ICE candidate gathering by setting the local offer.
942 ASSERT_TRUE(caller->SetLocalDescription(caller->CreateOffer()));
943
944 EXPECT_TRUE_WAIT(caller->IsIceGatheringDone(), kIceCandidatesTimeout);
945
946 caller->network()->RemoveInterface(kLocalAddress);
947
948 // Verify that the local candidates are not removed;
949 rtc::Thread::Current()->ProcessMessages(1000);
950 EXPECT_EQ(0, caller->observer()->num_candidates_removed_);
951}
952
953// The following group tests that when an offer includes a new ufrag or pwd
954// (indicating an ICE restart) the old candidates are removed and new candidates
955// added to the remote description.
956
Steve Anton46d926a2018-01-23 10:23:06 -0800957TEST_P(PeerConnectionIceTest, IceRestartOfferClearsExistingCandidate) {
Steve Antonf1c6db12017-10-13 11:13:35 -0700958 const SocketAddress kCallerAddress("1.1.1.1", 1111);
959
960 auto caller = CreatePeerConnectionWithAudioVideo();
961 auto callee = CreatePeerConnectionWithAudioVideo();
962
Amit Hilbuchae3df542019-01-07 12:13:08 -0800963 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700964 cricket::Candidate candidate = CreateLocalUdpCandidate(kCallerAddress);
965 AddCandidateToFirstTransport(&candidate, offer.get());
966
967 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
968
969 RTCOfferAnswerOptions options;
970 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800971 ASSERT_TRUE(
972 callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal(options)));
Steve Antonf1c6db12017-10-13 11:13:35 -0700973
974 EXPECT_EQ(0u, callee->GetIceCandidatesFromRemoteDescription().size());
975}
Steve Anton46d926a2018-01-23 10:23:06 -0800976TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -0700977 IceRestartOfferCandidateReplacesExistingCandidate) {
978 const SocketAddress kFirstCallerAddress("1.1.1.1", 1111);
979 const SocketAddress kRestartedCallerAddress("2.2.2.2", 2222);
980
981 auto caller = CreatePeerConnectionWithAudioVideo();
982 auto callee = CreatePeerConnectionWithAudioVideo();
983
Amit Hilbuchae3df542019-01-07 12:13:08 -0800984 auto offer = caller->CreateOfferAndSetAsLocal();
Steve Antonf1c6db12017-10-13 11:13:35 -0700985 cricket::Candidate old_candidate =
986 CreateLocalUdpCandidate(kFirstCallerAddress);
987 AddCandidateToFirstTransport(&old_candidate, offer.get());
988
989 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
990
991 RTCOfferAnswerOptions options;
992 options.ice_restart = true;
Amit Hilbuchae3df542019-01-07 12:13:08 -0800993 auto restart_offer = caller->CreateOfferAndSetAsLocal(options);
Steve Antonf1c6db12017-10-13 11:13:35 -0700994 cricket::Candidate new_candidate =
995 CreateLocalUdpCandidate(kRestartedCallerAddress);
996 AddCandidateToFirstTransport(&new_candidate, restart_offer.get());
997
998 ASSERT_TRUE(callee->SetRemoteDescription(std::move(restart_offer)));
999
1000 auto remote_candidates = callee->GetIceCandidatesFromRemoteDescription();
1001 ASSERT_EQ(1u, remote_candidates.size());
1002 EXPECT_PRED_FORMAT2(AssertCandidatesEqual, new_candidate,
1003 remote_candidates[0]->candidate());
1004}
1005
1006// Test that if there is not an ICE restart (i.e., nothing changes), then the
1007// answer to a later offer should have the same ufrag/pwd as the first answer.
Steve Anton46d926a2018-01-23 10:23:06 -08001008TEST_P(PeerConnectionIceTest, LaterAnswerHasSameIceCredentialsIfNoIceRestart) {
Steve Antonf1c6db12017-10-13 11:13:35 -07001009 auto caller = CreatePeerConnectionWithAudioVideo();
1010 auto callee = CreatePeerConnectionWithAudioVideo();
1011
1012 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1013 ASSERT_TRUE(
1014 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1015
1016 // Re-offer.
1017 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1018
1019 auto answer = callee->CreateAnswer();
1020 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
1021 auto* local_transport_desc =
1022 GetFirstTransportDescription(callee->pc()->local_description());
1023
1024 EXPECT_EQ(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
1025 EXPECT_EQ(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
1026}
1027
Henrik Boström79b69802019-07-18 11:16:56 +02001028TEST_P(PeerConnectionIceTest, RestartIceGeneratesNewCredentials) {
1029 auto caller = CreatePeerConnectionWithAudioVideo();
1030 auto callee = CreatePeerConnectionWithAudioVideo();
1031
1032 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1033 auto initial_ice_credentials =
1034 GetIceCredentials(caller->pc()->local_description());
1035 caller->pc()->RestartIce();
1036 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1037 auto restarted_ice_credentials =
1038 GetIceCredentials(caller->pc()->local_description());
1039 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1040}
1041
1042TEST_P(PeerConnectionIceTest,
1043 RestartIceWhileLocalOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1044 auto caller = CreatePeerConnectionWithAudioVideo();
1045 auto callee = CreatePeerConnectionWithAudioVideo();
1046
1047 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1048 auto initial_ice_credentials =
1049 GetIceCredentials(caller->pc()->local_description());
Artem Titov880fa812021-07-30 22:30:23 +02001050 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001051 // offerer.
1052 caller->pc()->RestartIce();
1053 ASSERT_TRUE(
1054 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1055 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1056 auto restarted_ice_credentials =
1057 GetIceCredentials(caller->pc()->local_description());
1058 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1059}
1060
1061TEST_P(PeerConnectionIceTest,
1062 RestartIceWhileRemoteOfferIsPendingGeneratesNewCredentialsInNextOffer) {
1063 auto caller = CreatePeerConnectionWithAudioVideo();
1064 auto callee = CreatePeerConnectionWithAudioVideo();
1065
1066 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1067 auto initial_ice_credentials =
1068 GetIceCredentials(caller->pc()->local_description());
1069 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001070 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001071 // answerer.
1072 caller->pc()->RestartIce();
1073 ASSERT_TRUE(
1074 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
1075 ASSERT_TRUE(caller->CreateOfferAndSetAsLocal());
1076 auto restarted_ice_credentials =
1077 GetIceCredentials(caller->pc()->local_description());
1078 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1079}
1080
1081TEST_P(PeerConnectionIceTest, RestartIceTriggeredByRemoteSide) {
1082 auto caller = CreatePeerConnectionWithAudioVideo();
1083 auto callee = CreatePeerConnectionWithAudioVideo();
1084
1085 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1086 auto initial_ice_credentials =
1087 GetIceCredentials(caller->pc()->local_description());
1088
Artem Titov880fa812021-07-30 22:30:23 +02001089 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001090 // restart ICE locally as well.
1091 callee->pc()->RestartIce();
1092 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1093
1094 auto restarted_ice_credentials =
1095 GetIceCredentials(caller->pc()->local_description());
1096 EXPECT_NE(initial_ice_credentials, restarted_ice_credentials);
1097}
1098
1099TEST_P(PeerConnectionIceTest, RestartIceCausesNegotiationNeeded) {
1100 auto caller = CreatePeerConnectionWithAudioVideo();
1101 auto callee = CreatePeerConnectionWithAudioVideo();
1102
1103 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001104 caller->observer()->clear_legacy_renegotiation_needed();
1105 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001106 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001107 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1108 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001109}
1110
1111// In Unified Plan, "onnegotiationneeded" is spec-compliant, including not
1112// firing multipe times in a row, or firing when returning to the stable
1113// signaling state if negotiation is still needed. In Plan B it fires any time
1114// something changes. As such, some tests are SdpSemantics-specific.
1115class PeerConnectionIceTestUnifiedPlan : public PeerConnectionIceBaseTest {
1116 protected:
1117 PeerConnectionIceTestUnifiedPlan()
1118 : PeerConnectionIceBaseTest(SdpSemantics::kUnifiedPlan) {}
1119};
1120
1121TEST_F(PeerConnectionIceTestUnifiedPlan,
1122 RestartIceWhileLocalOfferIsPendingCausesNegotiationNeededWhenStable) {
1123 auto caller = CreatePeerConnectionWithAudioVideo();
1124 auto callee = CreatePeerConnectionWithAudioVideo();
1125
1126 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001127 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001128 // offerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001129 caller->observer()->clear_legacy_renegotiation_needed();
1130 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001131 caller->pc()->RestartIce();
1132 // In Unified Plan, the event should not fire until we are back in the stable
1133 // signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001134 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1135 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001136 ASSERT_TRUE(
1137 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001138 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1139 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001140}
1141
1142TEST_F(PeerConnectionIceTestUnifiedPlan,
1143 RestartIceWhileRemoteOfferIsPendingCausesNegotiationNeededWhenStable) {
1144 auto caller = CreatePeerConnectionWithAudioVideo();
1145 auto callee = CreatePeerConnectionWithAudioVideo();
1146
1147 // Establish initial credentials as the caller.
1148 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1149 ASSERT_TRUE(caller->SetRemoteDescription(callee->CreateOfferAndSetAsLocal()));
Artem Titov880fa812021-07-30 22:30:23 +02001150 // ICE restart becomes needed while an O/A is pending and `caller` is the
Henrik Boström79b69802019-07-18 11:16:56 +02001151 // answerer.
Henrik Boströme574a312020-08-25 10:20:11 +02001152 caller->observer()->clear_legacy_renegotiation_needed();
1153 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001154 caller->pc()->RestartIce();
1155 // In Unified Plan, the event should not fire until we are back in the stable
1156 // signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001157 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1158 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001159 ASSERT_TRUE(
1160 callee->SetRemoteDescription(caller->CreateAnswerAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001161 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1162 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001163}
1164
1165TEST_F(PeerConnectionIceTestUnifiedPlan,
1166 RestartIceTriggeredByRemoteSideCauseNegotiationNotNeeded) {
1167 auto caller = CreatePeerConnectionWithAudioVideo();
1168 auto callee = CreatePeerConnectionWithAudioVideo();
1169
1170 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1171 // Local restart.
1172 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001173 caller->observer()->clear_legacy_renegotiation_needed();
1174 caller->observer()->clear_latest_negotiation_needed_event();
Artem Titov880fa812021-07-30 22:30:23 +02001175 // Remote restart and O/A exchange with `caller` as the answerer should
Henrik Boström79b69802019-07-18 11:16:56 +02001176 // restart ICE locally as well.
1177 callee->pc()->RestartIce();
1178 ASSERT_TRUE(callee->ExchangeOfferAnswerWith(caller.get()));
1179 // Having restarted ICE by the remote offer, we do not need to renegotiate ICE
1180 // credentials when back in the stable signaling state.
Henrik Boströme574a312020-08-25 10:20:11 +02001181 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1182 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001183}
1184
1185TEST_F(PeerConnectionIceTestUnifiedPlan,
1186 RestartIceTwiceDoesNotFireNegotiationNeededTwice) {
1187 auto caller = CreatePeerConnectionWithAudioVideo();
1188 auto callee = CreatePeerConnectionWithAudioVideo();
1189
1190 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
1191 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001192 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1193 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1194 caller->observer()->clear_legacy_renegotiation_needed();
1195 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001196 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001197 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1198 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001199}
1200
1201// In Plan B, "onnegotiationneeded" is not spec-compliant, firing based on if
1202// something changed rather than if negotiation is needed. In Unified Plan it
1203// fires according to spec. As such, some tests are SdpSemantics-specific.
1204class PeerConnectionIceTestPlanB : public PeerConnectionIceBaseTest {
1205 protected:
1206 PeerConnectionIceTestPlanB()
Florent Castelli15a38de2022-04-06 00:38:21 +02001207 : PeerConnectionIceBaseTest(SdpSemantics::kPlanB_DEPRECATED) {}
Henrik Boström79b69802019-07-18 11:16:56 +02001208};
1209
1210TEST_F(PeerConnectionIceTestPlanB,
1211 RestartIceWhileOfferIsPendingCausesNegotiationNeededImmediately) {
1212 auto caller = CreatePeerConnectionWithAudioVideo();
1213 auto callee = CreatePeerConnectionWithAudioVideo();
1214
1215 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
Henrik Boströme574a312020-08-25 10:20:11 +02001216 caller->observer()->clear_legacy_renegotiation_needed();
1217 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001218 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001219 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1220 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1221 caller->observer()->clear_legacy_renegotiation_needed();
1222 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001223 ASSERT_TRUE(
1224 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1225 // In Plan B, the event fired early so we don't expect it to fire now. This is
1226 // not spec-compliant but follows the pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001227 EXPECT_FALSE(caller->observer()->legacy_renegotiation_needed());
1228 EXPECT_FALSE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001229}
1230
1231TEST_F(PeerConnectionIceTestPlanB,
1232 RestartIceTwiceDoesFireNegotiationNeededTwice) {
1233 auto caller = CreatePeerConnectionWithAudioVideo();
1234 auto callee = CreatePeerConnectionWithAudioVideo();
1235
1236 ASSERT_TRUE(caller->ExchangeOfferAnswerWith(callee.get()));
Henrik Boströme574a312020-08-25 10:20:11 +02001237 caller->observer()->clear_legacy_renegotiation_needed();
1238 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001239 caller->pc()->RestartIce();
Henrik Boströme574a312020-08-25 10:20:11 +02001240 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1241 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
1242 caller->observer()->clear_legacy_renegotiation_needed();
1243 caller->observer()->clear_latest_negotiation_needed_event();
Henrik Boström79b69802019-07-18 11:16:56 +02001244 caller->pc()->RestartIce();
1245 // In Plan B, the event fires every time something changed, even if we have
1246 // already fired the event. This is not spec-compliant but follows the same
1247 // pattern of existing Plan B behavior.
Henrik Boströme574a312020-08-25 10:20:11 +02001248 EXPECT_TRUE(caller->observer()->legacy_renegotiation_needed());
1249 EXPECT_TRUE(caller->observer()->has_negotiation_needed_event());
Henrik Boström79b69802019-07-18 11:16:56 +02001250}
1251
Steve Antonf1c6db12017-10-13 11:13:35 -07001252// The following parameterized test verifies that if an offer is sent with a
1253// modified ICE ufrag and/or ICE pwd, then the answer should identify that the
1254// other side has initiated an ICE restart and generate a new ufrag and pwd.
1255// RFC 5245 says: "If the offer contained a change in the a=ice-ufrag or
1256// a=ice-pwd attributes compared to the previous SDP from the peer, it
1257// indicates that ICE is restarting for this media stream."
1258
Steve Anton46d926a2018-01-23 10:23:06 -08001259class PeerConnectionIceUfragPwdAnswerTest
1260 : public PeerConnectionIceBaseTest,
1261 public ::testing::WithParamInterface<
1262 std::tuple<SdpSemantics, std::tuple<bool, bool>>> {
Steve Antonf1c6db12017-10-13 11:13:35 -07001263 protected:
Steve Anton46d926a2018-01-23 10:23:06 -08001264 PeerConnectionIceUfragPwdAnswerTest()
1265 : PeerConnectionIceBaseTest(std::get<0>(GetParam())) {
1266 auto param = std::get<1>(GetParam());
1267 offer_new_ufrag_ = std::get<0>(param);
1268 offer_new_pwd_ = std::get<1>(param);
Steve Antonf1c6db12017-10-13 11:13:35 -07001269 }
1270
1271 bool offer_new_ufrag_;
1272 bool offer_new_pwd_;
1273};
1274
Steve Anton46d926a2018-01-23 10:23:06 -08001275TEST_P(PeerConnectionIceUfragPwdAnswerTest, TestIncludedInAnswer) {
Steve Antonf1c6db12017-10-13 11:13:35 -07001276 auto caller = CreatePeerConnectionWithAudioVideo();
1277 auto callee = CreatePeerConnectionWithAudioVideo();
1278
1279 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1280 ASSERT_TRUE(
1281 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1282
1283 auto offer = caller->CreateOffer();
1284 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
1285 if (offer_new_ufrag_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001286 offer_transport_desc->ice_ufrag += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001287 }
1288 if (offer_new_pwd_) {
Steve Anton71ff0732020-01-24 16:28:15 -08001289 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001290 }
1291
1292 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1293
1294 auto answer = callee->CreateAnswer();
1295 auto* answer_transport_desc = GetFirstTransportDescription(answer.get());
1296 auto* local_transport_desc =
1297 GetFirstTransportDescription(callee->pc()->local_description());
1298
1299 EXPECT_NE(answer_transport_desc->ice_ufrag, local_transport_desc->ice_ufrag);
1300 EXPECT_NE(answer_transport_desc->ice_pwd, local_transport_desc->ice_pwd);
1301}
1302
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001303INSTANTIATE_TEST_SUITE_P(
Steve Anton46d926a2018-01-23 10:23:06 -08001304 PeerConnectionIceTest,
1305 PeerConnectionIceUfragPwdAnswerTest,
Florent Castelli15a38de2022-04-06 00:38:21 +02001306 Combine(Values(SdpSemantics::kPlanB_DEPRECATED, SdpSemantics::kUnifiedPlan),
Steve Anton46d926a2018-01-23 10:23:06 -08001307 Values(std::make_pair(true, true), // Both changed.
1308 std::make_pair(true, false), // Only ufrag changed.
1309 std::make_pair(false, true)))); // Only pwd changed.
Steve Antonf1c6db12017-10-13 11:13:35 -07001310
1311// Test that if an ICE restart is offered on one media section, then the answer
1312// will only change ICE ufrag/pwd for that section and keep the other sections
1313// the same.
1314// Note that this only works if we have disabled BUNDLE, otherwise all media
1315// sections will share the same transport.
Steve Anton46d926a2018-01-23 10:23:06 -08001316TEST_P(PeerConnectionIceTest,
Steve Antonf1c6db12017-10-13 11:13:35 -07001317 CreateAnswerHasNewUfragPwdForOnlyMediaSectionWhichRestarted) {
1318 auto caller = CreatePeerConnectionWithAudioVideo();
1319 auto callee = CreatePeerConnectionWithAudioVideo();
1320
1321 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1322 ASSERT_TRUE(
1323 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1324
1325 RTCOfferAnswerOptions disable_bundle_options;
1326 disable_bundle_options.use_rtp_mux = false;
1327
1328 auto offer = caller->CreateOffer(disable_bundle_options);
1329
1330 // Signal ICE restart on the first media section.
1331 auto* offer_transport_desc = GetFirstTransportDescription(offer.get());
Steve Anton71ff0732020-01-24 16:28:15 -08001332 offer_transport_desc->ice_ufrag += "+new";
1333 offer_transport_desc->ice_pwd += "+new";
Steve Antonf1c6db12017-10-13 11:13:35 -07001334
1335 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1336
1337 auto answer = callee->CreateAnswer(disable_bundle_options);
1338 const auto& answer_transports = answer->description()->transport_infos();
1339 const auto& local_transports =
1340 callee->pc()->local_description()->description()->transport_infos();
1341
1342 EXPECT_NE(answer_transports[0].description.ice_ufrag,
1343 local_transports[0].description.ice_ufrag);
1344 EXPECT_NE(answer_transports[0].description.ice_pwd,
1345 local_transports[0].description.ice_pwd);
1346 EXPECT_EQ(answer_transports[1].description.ice_ufrag,
1347 local_transports[1].description.ice_ufrag);
1348 EXPECT_EQ(answer_transports[1].description.ice_pwd,
1349 local_transports[1].description.ice_pwd);
1350}
1351
Qingsi Wange1692722017-11-29 13:27:20 -08001352// Test that when the initial offerer (caller) uses the lite implementation of
1353// ICE and the callee uses the full implementation, the caller takes the
1354// CONTROLLED role and the callee takes the CONTROLLING role. This is specified
1355// in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001356TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001357 OfferFromLiteIceControlledAndAnswerFromFullIceControlling) {
1358 auto caller = CreatePeerConnectionWithAudioVideo();
1359 auto callee = CreatePeerConnectionWithAudioVideo();
1360
1361 auto offer = caller->CreateOffer();
1362 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1363 ASSERT_TRUE(
1364 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1365 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1366
1367 auto answer = callee->CreateAnswer();
1368 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_FULL);
1369 ASSERT_TRUE(
1370 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1371 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1372
1373 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(caller));
1374 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(callee));
1375}
1376
1377// Test that when the caller and the callee both use the lite implementation of
1378// ICE, the initial offerer (caller) takes the CONTROLLING role and the callee
1379// takes the CONTROLLED role. This is specified in RFC5245 Section 5.1.1.
Steve Anton46d926a2018-01-23 10:23:06 -08001380TEST_P(PeerConnectionIceTest,
Qingsi Wange1692722017-11-29 13:27:20 -08001381 OfferFromLiteIceControllingAndAnswerFromLiteIceControlled) {
1382 auto caller = CreatePeerConnectionWithAudioVideo();
1383 auto callee = CreatePeerConnectionWithAudioVideo();
1384
1385 auto offer = caller->CreateOffer();
1386 SetIceMode(offer.get(), cricket::IceMode::ICEMODE_LITE);
1387 ASSERT_TRUE(
1388 caller->SetLocalDescription(CloneSessionDescription(offer.get())));
1389 ASSERT_TRUE(callee->SetRemoteDescription(std::move(offer)));
1390
1391 auto answer = callee->CreateAnswer();
1392 SetIceMode(answer.get(), cricket::IceMode::ICEMODE_LITE);
1393 ASSERT_TRUE(
1394 callee->SetLocalDescription(CloneSessionDescription(answer.get())));
1395 ASSERT_TRUE(caller->SetRemoteDescription(std::move(answer)));
1396
1397 EXPECT_EQ(cricket::ICEROLE_CONTROLLING, GetIceRole(caller));
1398 EXPECT_EQ(cricket::ICEROLE_CONTROLLED, GetIceRole(callee));
1399}
1400
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001401INSTANTIATE_TEST_SUITE_P(PeerConnectionIceTest,
1402 PeerConnectionIceTest,
Florent Castelli15a38de2022-04-06 00:38:21 +02001403 Values(SdpSemantics::kPlanB_DEPRECATED,
Mirko Bonadeic84f6612019-01-31 12:20:57 +01001404 SdpSemantics::kUnifiedPlan));
Steve Anton46d926a2018-01-23 10:23:06 -08001405
Mirko Bonadei6a489f22019-04-09 15:11:12 +02001406class PeerConnectionIceConfigTest : public ::testing::Test {
Qingsi Wang4ff54432018-03-01 18:25:20 -08001407 protected:
1408 void SetUp() override {
1409 pc_factory_ = CreatePeerConnectionFactory(
1410 rtc::Thread::Current(), rtc::Thread::Current(), rtc::Thread::Current(),
1411 FakeAudioCaptureModule::Create(), CreateBuiltinAudioEncoderFactory(),
Anders Carlsson67537952018-05-03 11:28:29 +02001412 CreateBuiltinAudioDecoderFactory(), CreateBuiltinVideoEncoderFactory(),
1413 CreateBuiltinVideoDecoderFactory(), nullptr /* audio_mixer */,
1414 nullptr /* audio_processing */);
Qingsi Wang4ff54432018-03-01 18:25:20 -08001415 }
1416 void CreatePeerConnection(const RTCConfiguration& config) {
1417 std::unique_ptr<cricket::FakePortAllocator> port_allocator(
1418 new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr));
1419 port_allocator_ = port_allocator.get();
Florent Castelli72424402022-04-06 03:45:10 +02001420 PeerConnectionDependencies pc_dependencies(&observer_);
1421 pc_dependencies.allocator = std::move(port_allocator);
1422 auto result = pc_factory_->CreatePeerConnectionOrError(
1423 config, std::move(pc_dependencies));
1424 EXPECT_TRUE(result.ok());
1425 pc_ = result.MoveValue();
Qingsi Wang4ff54432018-03-01 18:25:20 -08001426 }
1427
1428 rtc::scoped_refptr<PeerConnectionFactoryInterface> pc_factory_ = nullptr;
1429 rtc::scoped_refptr<PeerConnectionInterface> pc_ = nullptr;
1430 cricket::FakePortAllocator* port_allocator_ = nullptr;
1431
1432 MockPeerConnectionObserver observer_;
1433};
1434
1435TEST_F(PeerConnectionIceConfigTest, SetStunCandidateKeepaliveInterval) {
1436 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001437 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Qingsi Wang4ff54432018-03-01 18:25:20 -08001438 config.stun_candidate_keepalive_interval = 123;
1439 config.ice_candidate_pool_size = 1;
1440 CreatePeerConnection(config);
1441 ASSERT_NE(port_allocator_, nullptr);
Danil Chapovalov66cadcc2018-06-19 16:47:43 +02001442 absl::optional<int> actual_stun_keepalive_interval =
Qingsi Wang4ff54432018-03-01 18:25:20 -08001443 port_allocator_->stun_candidate_keepalive_interval();
1444 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 123);
1445 config.stun_candidate_keepalive_interval = 321;
Niels Möller2579f0c2019-08-19 09:58:17 +02001446 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
Qingsi Wang4ff54432018-03-01 18:25:20 -08001447 actual_stun_keepalive_interval =
1448 port_allocator_->stun_candidate_keepalive_interval();
1449 EXPECT_EQ(actual_stun_keepalive_interval.value_or(-1), 321);
1450}
1451
Derek Bailey6c127a12021-04-15 12:42:41 -07001452TEST_F(PeerConnectionIceConfigTest, SetStableWritableConnectionInterval) {
1453 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001454 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001455 config.stable_writable_connection_ping_interval_ms = 3500;
1456 CreatePeerConnection(config);
1457 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1458 EXPECT_EQ(pc_->GetConfiguration().stable_writable_connection_ping_interval_ms,
1459 config.stable_writable_connection_ping_interval_ms);
1460}
1461
1462TEST_F(PeerConnectionIceConfigTest,
1463 SetStableWritableConnectionInterval_FailsValidation) {
1464 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001465 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001466 CreatePeerConnection(config);
1467 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1468 config.stable_writable_connection_ping_interval_ms = 5000;
1469 config.ice_check_interval_strong_connectivity = 7500;
1470 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1471}
1472
1473TEST_F(PeerConnectionIceConfigTest,
1474 SetStableWritableConnectionInterval_DefaultValue_FailsValidation) {
1475 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001476 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Derek Bailey6c127a12021-04-15 12:42:41 -07001477 CreatePeerConnection(config);
1478 ASSERT_TRUE(pc_->SetConfiguration(config).ok());
1479 config.ice_check_interval_strong_connectivity = 2500;
1480 EXPECT_TRUE(pc_->SetConfiguration(config).ok());
1481 config.ice_check_interval_strong_connectivity = 2501;
1482 EXPECT_FALSE(pc_->SetConfiguration(config).ok());
1483}
1484
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001485TEST_P(PeerConnectionIceTest, IceCredentialsCreateOffer) {
1486 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001487 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001488 config.ice_candidate_pool_size = 1;
1489 auto pc = CreatePeerConnectionWithAudioVideo(config);
1490 ASSERT_NE(pc->port_allocator_, nullptr);
1491 auto offer = pc->CreateOffer();
1492 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1493 ASSERT_EQ(1u, credentials.size());
1494
1495 auto* desc = offer->description();
1496 for (const auto& content : desc->contents()) {
1497 auto* transport_info = desc->GetTransportInfoByName(content.name);
1498 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1499 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1500 }
1501}
1502
1503TEST_P(PeerConnectionIceTest, IceCredentialsCreateAnswer) {
1504 RTCConfiguration config;
Henrik Boström62995db2022-01-03 09:58:10 +01001505 config.sdp_semantics = SdpSemantics::kUnifiedPlan;
Jonas Oreland1cd39fa2018-10-11 07:47:12 +02001506 config.ice_candidate_pool_size = 1;
1507 auto pc = CreatePeerConnectionWithAudioVideo(config);
1508 ASSERT_NE(pc->port_allocator_, nullptr);
1509 auto offer = pc->CreateOffer();
1510 ASSERT_TRUE(pc->SetRemoteDescription(std::move(offer)));
1511 auto answer = pc->CreateAnswer();
1512
1513 auto credentials = pc->port_allocator_->GetPooledIceCredentials();
1514 ASSERT_EQ(1u, credentials.size());
1515
1516 auto* desc = answer->description();
1517 for (const auto& content : desc->contents()) {
1518 auto* transport_info = desc->GetTransportInfoByName(content.name);
1519 EXPECT_EQ(transport_info->description.ice_ufrag, credentials[0].ufrag);
1520 EXPECT_EQ(transport_info->description.ice_pwd, credentials[0].pwd);
1521 }
1522}
1523
Steve Antonec47b572020-01-24 14:53:37 -08001524// Regression test for https://bugs.chromium.org/p/webrtc/issues/detail?id=4728
1525TEST_P(PeerConnectionIceTest, CloseDoesNotTransitionGatheringStateToComplete) {
1526 auto pc = CreatePeerConnectionWithAudioVideo();
1527 pc->pc()->Close();
1528 EXPECT_FALSE(pc->IsIceGatheringDone());
1529 EXPECT_EQ(PeerConnectionInterface::kIceGatheringNew,
1530 pc->pc()->ice_gathering_state());
1531}
1532
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001533TEST_P(PeerConnectionIceTest, PrefersMidOverMLineIndex) {
1534 const SocketAddress kCalleeAddress("1.1.1.1", 1111);
1535
1536 auto caller = CreatePeerConnectionWithAudioVideo();
1537 auto callee = CreatePeerConnectionWithAudioVideo();
1538
1539 ASSERT_TRUE(callee->SetRemoteDescription(caller->CreateOfferAndSetAsLocal()));
1540 ASSERT_TRUE(
1541 caller->SetRemoteDescription(callee->CreateAnswerAndSetAsLocal()));
1542
Artem Titovcfea2182021-08-10 01:22:31 +02001543 // `candidate.transport_name()` is empty.
Philipp Hancke31e06cb2021-02-26 09:23:53 +01001544 cricket::Candidate candidate = CreateLocalUdpCandidate(kCalleeAddress);
1545 auto* audio_content = cricket::GetFirstAudioContent(
1546 caller->pc()->local_description()->description());
1547 std::unique_ptr<IceCandidateInterface> ice_candidate =
1548 CreateIceCandidate(audio_content->name, 65535, candidate);
1549 EXPECT_TRUE(caller->pc()->AddIceCandidate(ice_candidate.get()));
1550 EXPECT_TRUE(caller->pc()->RemoveIceCandidates({candidate}));
1551}
1552
Steve Antonf1c6db12017-10-13 11:13:35 -07001553} // namespace webrtc