xref: /aosp_15_r20/external/webrtc/p2p/base/port_allocator_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright 2016 The WebRTC Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "p2p/base/port_allocator.h"
12 
13 #include <memory>
14 
15 #include "absl/strings/string_view.h"
16 #include "p2p/base/fake_port_allocator.h"
17 #include "rtc_base/thread.h"
18 #include "rtc_base/virtual_socket_server.h"
19 #include "test/gtest.h"
20 
21 static const char kContentName[] = "test content";
22 // Based on ICE_UFRAG_LENGTH
23 static const char kIceUfrag[] = "UF00";
24 // Based on ICE_PWD_LENGTH
25 static const char kIcePwd[] = "TESTICEPWD00000000000000";
26 static const char kTurnUsername[] = "test";
27 static const char kTurnPassword[] = "test";
28 constexpr uint64_t kTiebreakerDefault = 44444;
29 
30 class PortAllocatorTest : public ::testing::Test, public sigslot::has_slots<> {
31  public:
PortAllocatorTest()32   PortAllocatorTest()
33       : vss_(std::make_unique<rtc::VirtualSocketServer>()),
34         main_(vss_.get()),
35         packet_socket_factory_(
36             std::make_unique<rtc::BasicPacketSocketFactory>(vss_.get())),
37         allocator_(std::make_unique<cricket::FakePortAllocator>(
38             rtc::Thread::Current(),
39             packet_socket_factory_.get())) {
40     allocator_->SetIceTiebreaker(kTiebreakerDefault);
41   }
42 
43  protected:
SetConfigurationWithPoolSize(int candidate_pool_size)44   void SetConfigurationWithPoolSize(int candidate_pool_size) {
45     EXPECT_TRUE(allocator_->SetConfiguration(
46         cricket::ServerAddresses(), std::vector<cricket::RelayServerConfig>(),
47         candidate_pool_size, webrtc::NO_PRUNE));
48   }
49 
SetConfigurationWithPoolSizeExpectFailure(int candidate_pool_size)50   void SetConfigurationWithPoolSizeExpectFailure(int candidate_pool_size) {
51     EXPECT_FALSE(allocator_->SetConfiguration(
52         cricket::ServerAddresses(), std::vector<cricket::RelayServerConfig>(),
53         candidate_pool_size, webrtc::NO_PRUNE));
54   }
55 
CreateSession(absl::string_view content_name,int component,absl::string_view ice_ufrag,absl::string_view ice_pwd)56   std::unique_ptr<cricket::FakePortAllocatorSession> CreateSession(
57       absl::string_view content_name,
58       int component,
59       absl::string_view ice_ufrag,
60       absl::string_view ice_pwd) {
61     return std::unique_ptr<cricket::FakePortAllocatorSession>(
62         static_cast<cricket::FakePortAllocatorSession*>(
63             allocator_
64                 ->CreateSession(content_name, component, ice_ufrag, ice_pwd)
65                 .release()));
66   }
67 
GetPooledSession() const68   const cricket::FakePortAllocatorSession* GetPooledSession() const {
69     return static_cast<const cricket::FakePortAllocatorSession*>(
70         allocator_->GetPooledSession());
71   }
72 
TakePooledSession()73   std::unique_ptr<cricket::FakePortAllocatorSession> TakePooledSession() {
74     return std::unique_ptr<cricket::FakePortAllocatorSession>(
75         static_cast<cricket::FakePortAllocatorSession*>(
76             allocator_->TakePooledSession(kContentName, 0, kIceUfrag, kIcePwd)
77                 .release()));
78   }
79 
GetAllPooledSessionsReturnCount()80   int GetAllPooledSessionsReturnCount() {
81     int count = 0;
82     while (TakePooledSession() != nullptr) {
83       ++count;
84     }
85     return count;
86   }
87 
88   std::unique_ptr<rtc::VirtualSocketServer> vss_;
89   rtc::AutoSocketServerThread main_;
90   std::unique_ptr<rtc::PacketSocketFactory> packet_socket_factory_;
91   std::unique_ptr<cricket::FakePortAllocator> allocator_;
92   rtc::SocketAddress stun_server_1{"11.11.11.11", 3478};
93   rtc::SocketAddress stun_server_2{"22.22.22.22", 3478};
94   cricket::RelayServerConfig turn_server_1{"11.11.11.11",      3478,
95                                            kTurnUsername,      kTurnPassword,
96                                            cricket::PROTO_UDP, false};
97   cricket::RelayServerConfig turn_server_2{"22.22.22.22",      3478,
98                                            kTurnUsername,      kTurnPassword,
99                                            cricket::PROTO_UDP, false};
100 };
101 
TEST_F(PortAllocatorTest,TestDefaults)102 TEST_F(PortAllocatorTest, TestDefaults) {
103   EXPECT_EQ(0UL, allocator_->stun_servers().size());
104   EXPECT_EQ(0UL, allocator_->turn_servers().size());
105   EXPECT_EQ(0, allocator_->candidate_pool_size());
106   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
107 }
108 
109 // Call CreateSession and verify that the parameters passed in and the
110 // candidate filter are applied as expected.
TEST_F(PortAllocatorTest,CreateSession)111 TEST_F(PortAllocatorTest, CreateSession) {
112   allocator_->SetCandidateFilter(cricket::CF_RELAY);
113   auto session = CreateSession(kContentName, 1, kIceUfrag, kIcePwd);
114   ASSERT_NE(nullptr, session);
115   EXPECT_EQ(cricket::CF_RELAY, session->candidate_filter());
116   EXPECT_EQ(kContentName, session->content_name());
117   EXPECT_EQ(1, session->component());
118   EXPECT_EQ(kIceUfrag, session->ice_ufrag());
119   EXPECT_EQ(kIcePwd, session->ice_pwd());
120 }
121 
TEST_F(PortAllocatorTest,SetConfigurationUpdatesIceServers)122 TEST_F(PortAllocatorTest, SetConfigurationUpdatesIceServers) {
123   cricket::ServerAddresses stun_servers_1 = {stun_server_1};
124   std::vector<cricket::RelayServerConfig> turn_servers_1 = {turn_server_1};
125   EXPECT_TRUE(allocator_->SetConfiguration(stun_servers_1, turn_servers_1, 0,
126                                            webrtc::NO_PRUNE));
127   EXPECT_EQ(stun_servers_1, allocator_->stun_servers());
128   EXPECT_EQ(turn_servers_1, allocator_->turn_servers());
129 
130   // Update with a different set of servers.
131   cricket::ServerAddresses stun_servers_2 = {stun_server_2};
132   std::vector<cricket::RelayServerConfig> turn_servers_2 = {turn_server_2};
133   EXPECT_TRUE(allocator_->SetConfiguration(stun_servers_2, turn_servers_2, 0,
134                                            webrtc::NO_PRUNE));
135   EXPECT_EQ(stun_servers_2, allocator_->stun_servers());
136   EXPECT_EQ(turn_servers_2, allocator_->turn_servers());
137 }
138 
TEST_F(PortAllocatorTest,SetConfigurationUpdatesCandidatePoolSize)139 TEST_F(PortAllocatorTest, SetConfigurationUpdatesCandidatePoolSize) {
140   SetConfigurationWithPoolSize(2);
141   EXPECT_EQ(2, allocator_->candidate_pool_size());
142   SetConfigurationWithPoolSize(3);
143   EXPECT_EQ(3, allocator_->candidate_pool_size());
144   SetConfigurationWithPoolSize(1);
145   EXPECT_EQ(1, allocator_->candidate_pool_size());
146   SetConfigurationWithPoolSize(4);
147   EXPECT_EQ(4, allocator_->candidate_pool_size());
148 }
149 
150 // A negative pool size should just be treated as zero.
TEST_F(PortAllocatorTest,SetConfigurationWithNegativePoolSizeFails)151 TEST_F(PortAllocatorTest, SetConfigurationWithNegativePoolSizeFails) {
152   SetConfigurationWithPoolSizeExpectFailure(-1);
153 }
154 
155 // Test that if the candidate pool size is nonzero, pooled sessions are
156 // created, and StartGettingPorts is called on them.
TEST_F(PortAllocatorTest,SetConfigurationCreatesPooledSessions)157 TEST_F(PortAllocatorTest, SetConfigurationCreatesPooledSessions) {
158   SetConfigurationWithPoolSize(2);
159   auto session_1 = TakePooledSession();
160   auto session_2 = TakePooledSession();
161   ASSERT_NE(nullptr, session_1.get());
162   ASSERT_NE(nullptr, session_2.get());
163   EXPECT_EQ(1, session_1->port_config_count());
164   EXPECT_EQ(1, session_2->port_config_count());
165   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
166 }
167 
168 // Test that if the candidate pool size is increased, pooled sessions are
169 // created as necessary.
TEST_F(PortAllocatorTest,SetConfigurationCreatesMorePooledSessions)170 TEST_F(PortAllocatorTest, SetConfigurationCreatesMorePooledSessions) {
171   SetConfigurationWithPoolSize(1);
172   SetConfigurationWithPoolSize(2);
173   EXPECT_EQ(2, GetAllPooledSessionsReturnCount());
174 }
175 
176 // Test that if the candidate pool size is reduced, extra sessions are
177 // destroyed.
TEST_F(PortAllocatorTest,SetConfigurationDestroysPooledSessions)178 TEST_F(PortAllocatorTest, SetConfigurationDestroysPooledSessions) {
179   SetConfigurationWithPoolSize(2);
180   SetConfigurationWithPoolSize(1);
181   EXPECT_EQ(1, GetAllPooledSessionsReturnCount());
182 }
183 
184 // According to JSEP, existing pooled sessions should be destroyed and new
185 // ones created when the ICE servers change.
TEST_F(PortAllocatorTest,SetConfigurationRecreatesPooledSessionsWhenIceServersChange)186 TEST_F(PortAllocatorTest,
187        SetConfigurationRecreatesPooledSessionsWhenIceServersChange) {
188   cricket::ServerAddresses stun_servers_1 = {stun_server_1};
189   std::vector<cricket::RelayServerConfig> turn_servers_1 = {turn_server_1};
190   allocator_->SetConfiguration(stun_servers_1, turn_servers_1, 1,
191                                webrtc::NO_PRUNE);
192   EXPECT_EQ(stun_servers_1, allocator_->stun_servers());
193   EXPECT_EQ(turn_servers_1, allocator_->turn_servers());
194 
195   // Update with a different set of servers (and also change pool size).
196   cricket::ServerAddresses stun_servers_2 = {stun_server_2};
197   std::vector<cricket::RelayServerConfig> turn_servers_2 = {turn_server_2};
198   allocator_->SetConfiguration(stun_servers_2, turn_servers_2, 2,
199                                webrtc::NO_PRUNE);
200   EXPECT_EQ(stun_servers_2, allocator_->stun_servers());
201   EXPECT_EQ(turn_servers_2, allocator_->turn_servers());
202   auto session_1 = TakePooledSession();
203   auto session_2 = TakePooledSession();
204   ASSERT_NE(nullptr, session_1.get());
205   ASSERT_NE(nullptr, session_2.get());
206   EXPECT_EQ(stun_servers_2, session_1->stun_servers());
207   EXPECT_EQ(turn_servers_2, session_1->turn_servers());
208   EXPECT_EQ(stun_servers_2, session_2->stun_servers());
209   EXPECT_EQ(turn_servers_2, session_2->turn_servers());
210   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
211 }
212 
213 // According to JSEP, after SetLocalDescription, setting different ICE servers
214 // will not cause the pool to be refilled. This is implemented by the
215 // PeerConnection calling FreezeCandidatePool when a local description is set.
TEST_F(PortAllocatorTest,SetConfigurationDoesNotRecreatePooledSessionsAfterFreezeCandidatePool)216 TEST_F(PortAllocatorTest,
217        SetConfigurationDoesNotRecreatePooledSessionsAfterFreezeCandidatePool) {
218   cricket::ServerAddresses stun_servers_1 = {stun_server_1};
219   std::vector<cricket::RelayServerConfig> turn_servers_1 = {turn_server_1};
220   allocator_->SetConfiguration(stun_servers_1, turn_servers_1, 1,
221                                webrtc::NO_PRUNE);
222   EXPECT_EQ(stun_servers_1, allocator_->stun_servers());
223   EXPECT_EQ(turn_servers_1, allocator_->turn_servers());
224 
225   // Update with a different set of servers, but first freeze the pool.
226   allocator_->FreezeCandidatePool();
227   cricket::ServerAddresses stun_servers_2 = {stun_server_2};
228   std::vector<cricket::RelayServerConfig> turn_servers_2 = {turn_server_2};
229   allocator_->SetConfiguration(stun_servers_2, turn_servers_2, 2,
230                                webrtc::NO_PRUNE);
231   EXPECT_EQ(stun_servers_2, allocator_->stun_servers());
232   EXPECT_EQ(turn_servers_2, allocator_->turn_servers());
233   auto session = TakePooledSession();
234   ASSERT_NE(nullptr, session.get());
235   EXPECT_EQ(stun_servers_1, session->stun_servers());
236   EXPECT_EQ(turn_servers_1, session->turn_servers());
237   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
238 }
239 
TEST_F(PortAllocatorTest,GetPooledSessionReturnsNextSession)240 TEST_F(PortAllocatorTest, GetPooledSessionReturnsNextSession) {
241   SetConfigurationWithPoolSize(2);
242   auto peeked_session_1 = GetPooledSession();
243   auto session_1 = TakePooledSession();
244   EXPECT_EQ(session_1.get(), peeked_session_1);
245   auto peeked_session_2 = GetPooledSession();
246   auto session_2 = TakePooledSession();
247   EXPECT_EQ(session_2.get(), peeked_session_2);
248 }
249 
250 // Verify that subclasses of PortAllocatorSession are given a chance to update
251 // ICE parameters when TakePooledSession is called, and the base class updates
252 // the info itself.
TEST_F(PortAllocatorTest,TakePooledSessionUpdatesIceParameters)253 TEST_F(PortAllocatorTest, TakePooledSessionUpdatesIceParameters) {
254   SetConfigurationWithPoolSize(1);
255   auto peeked_session = GetPooledSession();
256   ASSERT_NE(nullptr, peeked_session);
257   EXPECT_EQ(0, peeked_session->transport_info_update_count());
258   std::unique_ptr<cricket::FakePortAllocatorSession> session(
259       static_cast<cricket::FakePortAllocatorSession*>(
260           allocator_->TakePooledSession(kContentName, 1, kIceUfrag, kIcePwd)
261               .release()));
262   EXPECT_EQ(1, session->transport_info_update_count());
263   EXPECT_EQ(kContentName, session->content_name());
264   EXPECT_EQ(1, session->component());
265   EXPECT_EQ(kIceUfrag, session->ice_ufrag());
266   EXPECT_EQ(kIcePwd, session->ice_pwd());
267 }
268 
269 // According to JSEP, candidate filtering should be done when the pooled
270 // candidates are surfaced to the application. This means when a pooled
271 // session is taken. So a pooled session should gather candidates
272 // unfiltered until it's returned by TakePooledSession.
TEST_F(PortAllocatorTest,TakePooledSessionUpdatesCandidateFilter)273 TEST_F(PortAllocatorTest, TakePooledSessionUpdatesCandidateFilter) {
274   allocator_->SetCandidateFilter(cricket::CF_RELAY);
275   SetConfigurationWithPoolSize(1);
276   auto peeked_session = GetPooledSession();
277   ASSERT_NE(nullptr, peeked_session);
278   EXPECT_EQ(cricket::CF_ALL, peeked_session->candidate_filter());
279   auto session = TakePooledSession();
280   EXPECT_EQ(cricket::CF_RELAY, session->candidate_filter());
281 }
282 
283 // Verify that after DiscardCandidatePool, TakePooledSession doesn't return
284 // anything.
TEST_F(PortAllocatorTest,DiscardCandidatePool)285 TEST_F(PortAllocatorTest, DiscardCandidatePool) {
286   SetConfigurationWithPoolSize(1);
287   allocator_->DiscardCandidatePool();
288   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
289 }
290 
TEST_F(PortAllocatorTest,RestrictIceCredentialsChange)291 TEST_F(PortAllocatorTest, RestrictIceCredentialsChange) {
292   SetConfigurationWithPoolSize(1);
293   EXPECT_EQ(1, GetAllPooledSessionsReturnCount());
294   allocator_->DiscardCandidatePool();
295 
296   // Only return pooled sessions with the ice credentials that
297   // match those requested in TakePooledSession().
298   allocator_->set_restrict_ice_credentials_change(true);
299   SetConfigurationWithPoolSize(1);
300   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
301   allocator_->DiscardCandidatePool();
302 
303   SetConfigurationWithPoolSize(1);
304   auto credentials = allocator_->GetPooledIceCredentials();
305   ASSERT_EQ(1u, credentials.size());
306   EXPECT_EQ(nullptr,
307             allocator_->TakePooledSession(kContentName, 0, kIceUfrag, kIcePwd));
308   EXPECT_NE(nullptr,
309             allocator_->TakePooledSession(kContentName, 0, credentials[0].ufrag,
310                                           credentials[0].pwd));
311   EXPECT_EQ(nullptr,
312             allocator_->TakePooledSession(kContentName, 0, credentials[0].ufrag,
313                                           credentials[0].pwd));
314   allocator_->DiscardCandidatePool();
315 }
316 
317 // Constants for testing candidates
318 const char kIpv4Address[] = "12.34.56.78";
319 const char kIpv4AddressWithPort[] = "12.34.56.78:443";
320 
TEST_F(PortAllocatorTest,SanitizeEmptyCandidateDefaultConfig)321 TEST_F(PortAllocatorTest, SanitizeEmptyCandidateDefaultConfig) {
322   cricket::Candidate input;
323   cricket::Candidate output = allocator_->SanitizeCandidate(input);
324   EXPECT_EQ("", output.address().ipaddr().ToString());
325 }
326 
TEST_F(PortAllocatorTest,SanitizeIpv4CandidateDefaultConfig)327 TEST_F(PortAllocatorTest, SanitizeIpv4CandidateDefaultConfig) {
328   cricket::Candidate input(1, "udp", rtc::SocketAddress(kIpv4Address, 443), 1,
329                            "username", "password", cricket::LOCAL_PORT_TYPE, 1,
330                            "foundation", 1, 1);
331   cricket::Candidate output = allocator_->SanitizeCandidate(input);
332   EXPECT_EQ(kIpv4AddressWithPort, output.address().ToString());
333   EXPECT_EQ(kIpv4Address, output.address().ipaddr().ToString());
334 }
335 
TEST_F(PortAllocatorTest,SanitizeIpv4CandidateMdnsObfuscationEnabled)336 TEST_F(PortAllocatorTest, SanitizeIpv4CandidateMdnsObfuscationEnabled) {
337   allocator_->SetMdnsObfuscationEnabledForTesting(true);
338   cricket::Candidate input(1, "udp", rtc::SocketAddress(kIpv4Address, 443), 1,
339                            "username", "password", cricket::LOCAL_PORT_TYPE, 1,
340                            "foundation", 1, 1);
341   cricket::Candidate output = allocator_->SanitizeCandidate(input);
342   EXPECT_NE(kIpv4AddressWithPort, output.address().ToString());
343   EXPECT_EQ("", output.address().ipaddr().ToString());
344 }
345 
TEST_F(PortAllocatorTest,SanitizePrflxCandidateMdnsObfuscationEnabled)346 TEST_F(PortAllocatorTest, SanitizePrflxCandidateMdnsObfuscationEnabled) {
347   allocator_->SetMdnsObfuscationEnabledForTesting(true);
348   // Create the candidate from an IP literal. This populates the hostname.
349   cricket::Candidate input(1, "udp", rtc::SocketAddress(kIpv4Address, 443), 1,
350                            "username", "password", cricket::PRFLX_PORT_TYPE, 1,
351                            "foundation", 1, 1);
352   cricket::Candidate output = allocator_->SanitizeCandidate(input);
353   EXPECT_NE(kIpv4AddressWithPort, output.address().ToString());
354   EXPECT_EQ("", output.address().ipaddr().ToString());
355 }
356 
TEST_F(PortAllocatorTest,SanitizeIpv4NonLiteralMdnsObfuscationEnabled)357 TEST_F(PortAllocatorTest, SanitizeIpv4NonLiteralMdnsObfuscationEnabled) {
358   // Create the candidate with an empty hostname.
359   allocator_->SetMdnsObfuscationEnabledForTesting(true);
360   rtc::IPAddress ip;
361   EXPECT_TRUE(IPFromString(kIpv4Address, &ip));
362   cricket::Candidate input(1, "udp", rtc::SocketAddress(ip, 443), 1, "username",
363                            "password", cricket::LOCAL_PORT_TYPE, 1,
364                            "foundation", 1, 1);
365   cricket::Candidate output = allocator_->SanitizeCandidate(input);
366   EXPECT_NE(kIpv4AddressWithPort, output.address().ToString());
367   EXPECT_EQ("", output.address().ipaddr().ToString());
368 }
369