• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "p2p/base/fake_port_allocator.h"
16 #include "rtc_base/thread.h"
17 #include "rtc_base/virtual_socket_server.h"
18 #include "test/gtest.h"
19 
20 static const char kContentName[] = "test content";
21 // Based on ICE_UFRAG_LENGTH
22 static const char kIceUfrag[] = "UF00";
23 // Based on ICE_PWD_LENGTH
24 static const char kIcePwd[] = "TESTICEPWD00000000000000";
25 static const char kTurnUsername[] = "test";
26 static const char kTurnPassword[] = "test";
27 
28 class PortAllocatorTest : public ::testing::Test, public sigslot::has_slots<> {
29  public:
PortAllocatorTest()30   PortAllocatorTest()
31       : vss_(new rtc::VirtualSocketServer()), main_(vss_.get()) {
32     allocator_.reset(
33         new cricket::FakePortAllocator(rtc::Thread::Current(), nullptr));
34   }
35 
36  protected:
SetConfigurationWithPoolSize(int candidate_pool_size)37   void SetConfigurationWithPoolSize(int candidate_pool_size) {
38     EXPECT_TRUE(allocator_->SetConfiguration(
39         cricket::ServerAddresses(), std::vector<cricket::RelayServerConfig>(),
40         candidate_pool_size, webrtc::NO_PRUNE));
41   }
42 
SetConfigurationWithPoolSizeExpectFailure(int candidate_pool_size)43   void SetConfigurationWithPoolSizeExpectFailure(int candidate_pool_size) {
44     EXPECT_FALSE(allocator_->SetConfiguration(
45         cricket::ServerAddresses(), std::vector<cricket::RelayServerConfig>(),
46         candidate_pool_size, webrtc::NO_PRUNE));
47   }
48 
CreateSession(const std::string & content_name,int component,const std::string & ice_ufrag,const std::string & ice_pwd)49   std::unique_ptr<cricket::FakePortAllocatorSession> CreateSession(
50       const std::string& content_name,
51       int component,
52       const std::string& ice_ufrag,
53       const std::string& ice_pwd) {
54     return std::unique_ptr<cricket::FakePortAllocatorSession>(
55         static_cast<cricket::FakePortAllocatorSession*>(
56             allocator_
57                 ->CreateSession(content_name, component, ice_ufrag, ice_pwd)
58                 .release()));
59   }
60 
GetPooledSession() const61   const cricket::FakePortAllocatorSession* GetPooledSession() const {
62     return static_cast<const cricket::FakePortAllocatorSession*>(
63         allocator_->GetPooledSession());
64   }
65 
TakePooledSession()66   std::unique_ptr<cricket::FakePortAllocatorSession> TakePooledSession() {
67     return std::unique_ptr<cricket::FakePortAllocatorSession>(
68         static_cast<cricket::FakePortAllocatorSession*>(
69             allocator_->TakePooledSession(kContentName, 0, kIceUfrag, kIcePwd)
70                 .release()));
71   }
72 
GetAllPooledSessionsReturnCount()73   int GetAllPooledSessionsReturnCount() {
74     int count = 0;
75     while (TakePooledSession() != nullptr) {
76       ++count;
77     }
78     return count;
79   }
80 
81   std::unique_ptr<rtc::VirtualSocketServer> vss_;
82   rtc::AutoSocketServerThread main_;
83   std::unique_ptr<cricket::FakePortAllocator> allocator_;
84   rtc::SocketAddress stun_server_1{"11.11.11.11", 3478};
85   rtc::SocketAddress stun_server_2{"22.22.22.22", 3478};
86   cricket::RelayServerConfig turn_server_1{"11.11.11.11",      3478,
87                                            kTurnUsername,      kTurnPassword,
88                                            cricket::PROTO_UDP, false};
89   cricket::RelayServerConfig turn_server_2{"22.22.22.22",      3478,
90                                            kTurnUsername,      kTurnPassword,
91                                            cricket::PROTO_UDP, false};
92 };
93 
TEST_F(PortAllocatorTest,TestDefaults)94 TEST_F(PortAllocatorTest, TestDefaults) {
95   EXPECT_EQ(0UL, allocator_->stun_servers().size());
96   EXPECT_EQ(0UL, allocator_->turn_servers().size());
97   EXPECT_EQ(0, allocator_->candidate_pool_size());
98   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
99 }
100 
101 // Call CreateSession and verify that the parameters passed in and the
102 // candidate filter are applied as expected.
TEST_F(PortAllocatorTest,CreateSession)103 TEST_F(PortAllocatorTest, CreateSession) {
104   allocator_->SetCandidateFilter(cricket::CF_RELAY);
105   auto session = CreateSession(kContentName, 1, kIceUfrag, kIcePwd);
106   ASSERT_NE(nullptr, session);
107   EXPECT_EQ(cricket::CF_RELAY, session->candidate_filter());
108   EXPECT_EQ(kContentName, session->content_name());
109   EXPECT_EQ(1, session->component());
110   EXPECT_EQ(kIceUfrag, session->ice_ufrag());
111   EXPECT_EQ(kIcePwd, session->ice_pwd());
112 }
113 
TEST_F(PortAllocatorTest,SetConfigurationUpdatesIceServers)114 TEST_F(PortAllocatorTest, SetConfigurationUpdatesIceServers) {
115   cricket::ServerAddresses stun_servers_1 = {stun_server_1};
116   std::vector<cricket::RelayServerConfig> turn_servers_1 = {turn_server_1};
117   EXPECT_TRUE(allocator_->SetConfiguration(stun_servers_1, turn_servers_1, 0,
118                                            webrtc::NO_PRUNE));
119   EXPECT_EQ(stun_servers_1, allocator_->stun_servers());
120   EXPECT_EQ(turn_servers_1, allocator_->turn_servers());
121 
122   // Update with a different set of servers.
123   cricket::ServerAddresses stun_servers_2 = {stun_server_2};
124   std::vector<cricket::RelayServerConfig> turn_servers_2 = {turn_server_2};
125   EXPECT_TRUE(allocator_->SetConfiguration(stun_servers_2, turn_servers_2, 0,
126                                            webrtc::NO_PRUNE));
127   EXPECT_EQ(stun_servers_2, allocator_->stun_servers());
128   EXPECT_EQ(turn_servers_2, allocator_->turn_servers());
129 }
130 
TEST_F(PortAllocatorTest,SetConfigurationUpdatesCandidatePoolSize)131 TEST_F(PortAllocatorTest, SetConfigurationUpdatesCandidatePoolSize) {
132   SetConfigurationWithPoolSize(2);
133   EXPECT_EQ(2, allocator_->candidate_pool_size());
134   SetConfigurationWithPoolSize(3);
135   EXPECT_EQ(3, allocator_->candidate_pool_size());
136   SetConfigurationWithPoolSize(1);
137   EXPECT_EQ(1, allocator_->candidate_pool_size());
138   SetConfigurationWithPoolSize(4);
139   EXPECT_EQ(4, allocator_->candidate_pool_size());
140 }
141 
142 // A negative pool size should just be treated as zero.
TEST_F(PortAllocatorTest,SetConfigurationWithNegativePoolSizeFails)143 TEST_F(PortAllocatorTest, SetConfigurationWithNegativePoolSizeFails) {
144   SetConfigurationWithPoolSizeExpectFailure(-1);
145 }
146 
147 // Test that if the candidate pool size is nonzero, pooled sessions are
148 // created, and StartGettingPorts is called on them.
TEST_F(PortAllocatorTest,SetConfigurationCreatesPooledSessions)149 TEST_F(PortAllocatorTest, SetConfigurationCreatesPooledSessions) {
150   SetConfigurationWithPoolSize(2);
151   auto session_1 = TakePooledSession();
152   auto session_2 = TakePooledSession();
153   ASSERT_NE(nullptr, session_1.get());
154   ASSERT_NE(nullptr, session_2.get());
155   EXPECT_EQ(1, session_1->port_config_count());
156   EXPECT_EQ(1, session_2->port_config_count());
157   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
158 }
159 
160 // Test that if the candidate pool size is increased, pooled sessions are
161 // created as necessary.
TEST_F(PortAllocatorTest,SetConfigurationCreatesMorePooledSessions)162 TEST_F(PortAllocatorTest, SetConfigurationCreatesMorePooledSessions) {
163   SetConfigurationWithPoolSize(1);
164   SetConfigurationWithPoolSize(2);
165   EXPECT_EQ(2, GetAllPooledSessionsReturnCount());
166 }
167 
168 // Test that if the candidate pool size is reduced, extra sessions are
169 // destroyed.
TEST_F(PortAllocatorTest,SetConfigurationDestroysPooledSessions)170 TEST_F(PortAllocatorTest, SetConfigurationDestroysPooledSessions) {
171   SetConfigurationWithPoolSize(2);
172   SetConfigurationWithPoolSize(1);
173   EXPECT_EQ(1, GetAllPooledSessionsReturnCount());
174 }
175 
176 // According to JSEP, existing pooled sessions should be destroyed and new
177 // ones created when the ICE servers change.
TEST_F(PortAllocatorTest,SetConfigurationRecreatesPooledSessionsWhenIceServersChange)178 TEST_F(PortAllocatorTest,
179        SetConfigurationRecreatesPooledSessionsWhenIceServersChange) {
180   cricket::ServerAddresses stun_servers_1 = {stun_server_1};
181   std::vector<cricket::RelayServerConfig> turn_servers_1 = {turn_server_1};
182   allocator_->SetConfiguration(stun_servers_1, turn_servers_1, 1,
183                                webrtc::NO_PRUNE);
184   EXPECT_EQ(stun_servers_1, allocator_->stun_servers());
185   EXPECT_EQ(turn_servers_1, allocator_->turn_servers());
186 
187   // Update with a different set of servers (and also change pool size).
188   cricket::ServerAddresses stun_servers_2 = {stun_server_2};
189   std::vector<cricket::RelayServerConfig> turn_servers_2 = {turn_server_2};
190   allocator_->SetConfiguration(stun_servers_2, turn_servers_2, 2,
191                                webrtc::NO_PRUNE);
192   EXPECT_EQ(stun_servers_2, allocator_->stun_servers());
193   EXPECT_EQ(turn_servers_2, allocator_->turn_servers());
194   auto session_1 = TakePooledSession();
195   auto session_2 = TakePooledSession();
196   ASSERT_NE(nullptr, session_1.get());
197   ASSERT_NE(nullptr, session_2.get());
198   EXPECT_EQ(stun_servers_2, session_1->stun_servers());
199   EXPECT_EQ(turn_servers_2, session_1->turn_servers());
200   EXPECT_EQ(stun_servers_2, session_2->stun_servers());
201   EXPECT_EQ(turn_servers_2, session_2->turn_servers());
202   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
203 }
204 
205 // According to JSEP, after SetLocalDescription, setting different ICE servers
206 // will not cause the pool to be refilled. This is implemented by the
207 // PeerConnection calling FreezeCandidatePool when a local description is set.
TEST_F(PortAllocatorTest,SetConfigurationDoesNotRecreatePooledSessionsAfterFreezeCandidatePool)208 TEST_F(PortAllocatorTest,
209        SetConfigurationDoesNotRecreatePooledSessionsAfterFreezeCandidatePool) {
210   cricket::ServerAddresses stun_servers_1 = {stun_server_1};
211   std::vector<cricket::RelayServerConfig> turn_servers_1 = {turn_server_1};
212   allocator_->SetConfiguration(stun_servers_1, turn_servers_1, 1,
213                                webrtc::NO_PRUNE);
214   EXPECT_EQ(stun_servers_1, allocator_->stun_servers());
215   EXPECT_EQ(turn_servers_1, allocator_->turn_servers());
216 
217   // Update with a different set of servers, but first freeze the pool.
218   allocator_->FreezeCandidatePool();
219   cricket::ServerAddresses stun_servers_2 = {stun_server_2};
220   std::vector<cricket::RelayServerConfig> turn_servers_2 = {turn_server_2};
221   allocator_->SetConfiguration(stun_servers_2, turn_servers_2, 2,
222                                webrtc::NO_PRUNE);
223   EXPECT_EQ(stun_servers_2, allocator_->stun_servers());
224   EXPECT_EQ(turn_servers_2, allocator_->turn_servers());
225   auto session = TakePooledSession();
226   ASSERT_NE(nullptr, session.get());
227   EXPECT_EQ(stun_servers_1, session->stun_servers());
228   EXPECT_EQ(turn_servers_1, session->turn_servers());
229   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
230 }
231 
TEST_F(PortAllocatorTest,GetPooledSessionReturnsNextSession)232 TEST_F(PortAllocatorTest, GetPooledSessionReturnsNextSession) {
233   SetConfigurationWithPoolSize(2);
234   auto peeked_session_1 = GetPooledSession();
235   auto session_1 = TakePooledSession();
236   EXPECT_EQ(session_1.get(), peeked_session_1);
237   auto peeked_session_2 = GetPooledSession();
238   auto session_2 = TakePooledSession();
239   EXPECT_EQ(session_2.get(), peeked_session_2);
240 }
241 
242 // Verify that subclasses of PortAllocatorSession are given a chance to update
243 // ICE parameters when TakePooledSession is called, and the base class updates
244 // the info itself.
TEST_F(PortAllocatorTest,TakePooledSessionUpdatesIceParameters)245 TEST_F(PortAllocatorTest, TakePooledSessionUpdatesIceParameters) {
246   SetConfigurationWithPoolSize(1);
247   auto peeked_session = GetPooledSession();
248   ASSERT_NE(nullptr, peeked_session);
249   EXPECT_EQ(0, peeked_session->transport_info_update_count());
250   std::unique_ptr<cricket::FakePortAllocatorSession> session(
251       static_cast<cricket::FakePortAllocatorSession*>(
252           allocator_->TakePooledSession(kContentName, 1, kIceUfrag, kIcePwd)
253               .release()));
254   EXPECT_EQ(1, session->transport_info_update_count());
255   EXPECT_EQ(kContentName, session->content_name());
256   EXPECT_EQ(1, session->component());
257   EXPECT_EQ(kIceUfrag, session->ice_ufrag());
258   EXPECT_EQ(kIcePwd, session->ice_pwd());
259 }
260 
261 // According to JSEP, candidate filtering should be done when the pooled
262 // candidates are surfaced to the application. This means when a pooled
263 // session is taken. So a pooled session should gather candidates
264 // unfiltered until it's returned by TakePooledSession.
TEST_F(PortAllocatorTest,TakePooledSessionUpdatesCandidateFilter)265 TEST_F(PortAllocatorTest, TakePooledSessionUpdatesCandidateFilter) {
266   allocator_->SetCandidateFilter(cricket::CF_RELAY);
267   SetConfigurationWithPoolSize(1);
268   auto peeked_session = GetPooledSession();
269   ASSERT_NE(nullptr, peeked_session);
270   EXPECT_EQ(cricket::CF_ALL, peeked_session->candidate_filter());
271   auto session = TakePooledSession();
272   EXPECT_EQ(cricket::CF_RELAY, session->candidate_filter());
273 }
274 
275 // Verify that after DiscardCandidatePool, TakePooledSession doesn't return
276 // anything.
TEST_F(PortAllocatorTest,DiscardCandidatePool)277 TEST_F(PortAllocatorTest, DiscardCandidatePool) {
278   SetConfigurationWithPoolSize(1);
279   allocator_->DiscardCandidatePool();
280   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
281 }
282 
TEST_F(PortAllocatorTest,RestrictIceCredentialsChange)283 TEST_F(PortAllocatorTest, RestrictIceCredentialsChange) {
284   SetConfigurationWithPoolSize(1);
285   EXPECT_EQ(1, GetAllPooledSessionsReturnCount());
286   allocator_->DiscardCandidatePool();
287 
288   // Only return pooled sessions with the ice credentials that
289   // match those requested in TakePooledSession().
290   allocator_->set_restrict_ice_credentials_change(true);
291   SetConfigurationWithPoolSize(1);
292   EXPECT_EQ(0, GetAllPooledSessionsReturnCount());
293   allocator_->DiscardCandidatePool();
294 
295   SetConfigurationWithPoolSize(1);
296   auto credentials = allocator_->GetPooledIceCredentials();
297   ASSERT_EQ(1u, credentials.size());
298   EXPECT_EQ(nullptr,
299             allocator_->TakePooledSession(kContentName, 0, kIceUfrag, kIcePwd));
300   EXPECT_NE(nullptr,
301             allocator_->TakePooledSession(kContentName, 0, credentials[0].ufrag,
302                                           credentials[0].pwd));
303   EXPECT_EQ(nullptr,
304             allocator_->TakePooledSession(kContentName, 0, credentials[0].ufrag,
305                                           credentials[0].pwd));
306   allocator_->DiscardCandidatePool();
307 }
308