• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/socket/socks_client_socket_pool.h"
6 
7 #include "base/callback.h"
8 #include "base/compiler_specific.h"
9 #include "base/time.h"
10 #include "net/base/mock_host_resolver.h"
11 #include "net/base/net_errors.h"
12 #include "net/base/test_completion_callback.h"
13 #include "net/socket/client_socket_factory.h"
14 #include "net/socket/client_socket_handle.h"
15 #include "net/socket/client_socket_pool_histograms.h"
16 #include "net/socket/socket_test_util.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 namespace net {
20 
21 namespace {
22 
23 const int kMaxSockets = 32;
24 const int kMaxSocketsPerGroup = 6;
25 
26 class SOCKSClientSocketPoolTest : public testing::Test {
27  protected:
28   class SOCKS5MockData {
29    public:
SOCKS5MockData(bool async)30     explicit SOCKS5MockData(bool async) {
31       writes_.reset(new MockWrite[3]);
32       writes_[0] = MockWrite(async, kSOCKS5GreetRequest,
33                              kSOCKS5GreetRequestLength);
34       writes_[1] = MockWrite(async, kSOCKS5OkRequest, kSOCKS5OkRequestLength);
35       writes_[2] = MockWrite(async, 0);
36 
37       reads_.reset(new MockRead[3]);
38       reads_[0] = MockRead(async, kSOCKS5GreetResponse,
39                            kSOCKS5GreetResponseLength);
40       reads_[1] = MockRead(async, kSOCKS5OkResponse, kSOCKS5OkResponseLength);
41       reads_[2] = MockRead(async, 0);
42 
43       data_.reset(new StaticSocketDataProvider(reads_.get(), 3,
44                                                writes_.get(), 3));
45     }
46 
data_provider()47     SocketDataProvider* data_provider() { return data_.get(); }
48 
49    private:
50     scoped_ptr<StaticSocketDataProvider> data_;
51     scoped_array<MockWrite> writes_;
52     scoped_array<MockWrite> reads_;
53   };
54 
SOCKSClientSocketPoolTest()55   SOCKSClientSocketPoolTest()
56       : ignored_transport_socket_params_(new TransportSocketParams(
57             HostPortPair("proxy", 80), MEDIUM, GURL(), false, false)),
58         transport_histograms_("MockTCP"),
59         transport_socket_pool_(
60             kMaxSockets, kMaxSocketsPerGroup,
61             &transport_histograms_,
62             &transport_client_socket_factory_),
63         ignored_socket_params_(new SOCKSSocketParams(
64             ignored_transport_socket_params_, true, HostPortPair("host", 80),
65             MEDIUM, GURL())),
66         socks_histograms_("SOCKSUnitTest"),
67         pool_(kMaxSockets, kMaxSocketsPerGroup,
68               &socks_histograms_,
69               NULL,
70               &transport_socket_pool_,
71               NULL) {
72   }
73 
~SOCKSClientSocketPoolTest()74   virtual ~SOCKSClientSocketPoolTest() {}
75 
StartRequest(const std::string & group_name,RequestPriority priority)76   int StartRequest(const std::string& group_name, RequestPriority priority) {
77     return test_base_.StartRequestUsingPool(
78         &pool_, group_name, priority, ignored_socket_params_);
79   }
80 
GetOrderOfRequest(size_t index) const81   int GetOrderOfRequest(size_t index) const {
82     return test_base_.GetOrderOfRequest(index);
83   }
84 
requests()85   ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); }
86 
87   scoped_refptr<TransportSocketParams> ignored_transport_socket_params_;
88   ClientSocketPoolHistograms transport_histograms_;
89   MockClientSocketFactory transport_client_socket_factory_;
90   MockTransportClientSocketPool transport_socket_pool_;
91 
92   scoped_refptr<SOCKSSocketParams> ignored_socket_params_;
93   ClientSocketPoolHistograms socks_histograms_;
94   SOCKSClientSocketPool pool_;
95   ClientSocketPoolTest test_base_;
96 };
97 
TEST_F(SOCKSClientSocketPoolTest,Simple)98 TEST_F(SOCKSClientSocketPoolTest, Simple) {
99   SOCKS5MockData data(false);
100   data.data_provider()->set_connect_data(MockConnect(false, 0));
101   transport_client_socket_factory_.AddSocketDataProvider(data.data_provider());
102 
103   ClientSocketHandle handle;
104   int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, &pool_,
105                        BoundNetLog());
106   EXPECT_EQ(OK, rv);
107   EXPECT_TRUE(handle.is_initialized());
108   EXPECT_TRUE(handle.socket());
109 }
110 
TEST_F(SOCKSClientSocketPoolTest,Async)111 TEST_F(SOCKSClientSocketPoolTest, Async) {
112   SOCKS5MockData data(true);
113   transport_client_socket_factory_.AddSocketDataProvider(data.data_provider());
114 
115   TestCompletionCallback callback;
116   ClientSocketHandle handle;
117   int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, &pool_,
118                        BoundNetLog());
119   EXPECT_EQ(ERR_IO_PENDING, rv);
120   EXPECT_FALSE(handle.is_initialized());
121   EXPECT_FALSE(handle.socket());
122 
123   EXPECT_EQ(OK, callback.WaitForResult());
124   EXPECT_TRUE(handle.is_initialized());
125   EXPECT_TRUE(handle.socket());
126 }
127 
TEST_F(SOCKSClientSocketPoolTest,TransportConnectError)128 TEST_F(SOCKSClientSocketPoolTest, TransportConnectError) {
129   scoped_ptr<SocketDataProvider> socket_data(new StaticSocketDataProvider());
130   socket_data->set_connect_data(MockConnect(false, ERR_CONNECTION_REFUSED));
131   transport_client_socket_factory_.AddSocketDataProvider(socket_data.get());
132 
133   ClientSocketHandle handle;
134   int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, &pool_,
135                        BoundNetLog());
136   EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, rv);
137   EXPECT_FALSE(handle.is_initialized());
138   EXPECT_FALSE(handle.socket());
139 }
140 
TEST_F(SOCKSClientSocketPoolTest,AsyncTransportConnectError)141 TEST_F(SOCKSClientSocketPoolTest, AsyncTransportConnectError) {
142   scoped_ptr<SocketDataProvider> socket_data(new StaticSocketDataProvider());
143   socket_data->set_connect_data(MockConnect(true, ERR_CONNECTION_REFUSED));
144   transport_client_socket_factory_.AddSocketDataProvider(socket_data.get());
145 
146   TestCompletionCallback callback;
147   ClientSocketHandle handle;
148   int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, &pool_,
149                        BoundNetLog());
150   EXPECT_EQ(ERR_IO_PENDING, rv);
151   EXPECT_FALSE(handle.is_initialized());
152   EXPECT_FALSE(handle.socket());
153 
154   EXPECT_EQ(ERR_PROXY_CONNECTION_FAILED, callback.WaitForResult());
155   EXPECT_FALSE(handle.is_initialized());
156   EXPECT_FALSE(handle.socket());
157 }
158 
TEST_F(SOCKSClientSocketPoolTest,SOCKSConnectError)159 TEST_F(SOCKSClientSocketPoolTest, SOCKSConnectError) {
160   MockRead failed_read[] = {
161     MockRead(false, 0),
162   };
163   scoped_ptr<SocketDataProvider> socket_data(new StaticSocketDataProvider(
164         failed_read, arraysize(failed_read), NULL, 0));
165   socket_data->set_connect_data(MockConnect(false, 0));
166   transport_client_socket_factory_.AddSocketDataProvider(socket_data.get());
167 
168   ClientSocketHandle handle;
169   EXPECT_EQ(0, transport_socket_pool_.release_count());
170   int rv = handle.Init("a", ignored_socket_params_, LOW, NULL, &pool_,
171                        BoundNetLog());
172   EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, rv);
173   EXPECT_FALSE(handle.is_initialized());
174   EXPECT_FALSE(handle.socket());
175   EXPECT_EQ(1, transport_socket_pool_.release_count());
176 }
177 
TEST_F(SOCKSClientSocketPoolTest,AsyncSOCKSConnectError)178 TEST_F(SOCKSClientSocketPoolTest, AsyncSOCKSConnectError) {
179   MockRead failed_read[] = {
180     MockRead(true, 0),
181   };
182   scoped_ptr<SocketDataProvider> socket_data(new StaticSocketDataProvider(
183         failed_read, arraysize(failed_read), NULL, 0));
184   socket_data->set_connect_data(MockConnect(false, 0));
185   transport_client_socket_factory_.AddSocketDataProvider(socket_data.get());
186 
187   TestCompletionCallback callback;
188   ClientSocketHandle handle;
189   EXPECT_EQ(0, transport_socket_pool_.release_count());
190   int rv = handle.Init("a", ignored_socket_params_, LOW, &callback, &pool_,
191                        BoundNetLog());
192   EXPECT_EQ(ERR_IO_PENDING, rv);
193   EXPECT_FALSE(handle.is_initialized());
194   EXPECT_FALSE(handle.socket());
195 
196   EXPECT_EQ(ERR_SOCKS_CONNECTION_FAILED, callback.WaitForResult());
197   EXPECT_FALSE(handle.is_initialized());
198   EXPECT_FALSE(handle.socket());
199   EXPECT_EQ(1, transport_socket_pool_.release_count());
200 }
201 
TEST_F(SOCKSClientSocketPoolTest,CancelDuringTransportConnect)202 TEST_F(SOCKSClientSocketPoolTest, CancelDuringTransportConnect) {
203   SOCKS5MockData data(false);
204   transport_client_socket_factory_.AddSocketDataProvider(data.data_provider());
205   // We need two connections because the pool base lets one cancelled
206   // connect job proceed for potential future use.
207   SOCKS5MockData data2(false);
208   transport_client_socket_factory_.AddSocketDataProvider(data2.data_provider());
209 
210   EXPECT_EQ(0, transport_socket_pool_.cancel_count());
211   int rv = StartRequest("a", LOW);
212   EXPECT_EQ(ERR_IO_PENDING, rv);
213 
214   rv = StartRequest("a", LOW);
215   EXPECT_EQ(ERR_IO_PENDING, rv);
216 
217   pool_.CancelRequest("a", (*requests())[0]->handle());
218   pool_.CancelRequest("a", (*requests())[1]->handle());
219   // Requests in the connect phase don't actually get cancelled.
220   EXPECT_EQ(0, transport_socket_pool_.cancel_count());
221 
222   // Now wait for the TCP sockets to connect.
223   MessageLoop::current()->RunAllPending();
224 
225   EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(1));
226   EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(2));
227   EXPECT_EQ(0, transport_socket_pool_.cancel_count());
228   EXPECT_EQ(2, pool_.IdleSocketCount());
229 
230   (*requests())[0]->handle()->Reset();
231   (*requests())[1]->handle()->Reset();
232 }
233 
TEST_F(SOCKSClientSocketPoolTest,CancelDuringSOCKSConnect)234 TEST_F(SOCKSClientSocketPoolTest, CancelDuringSOCKSConnect) {
235   SOCKS5MockData data(true);
236   data.data_provider()->set_connect_data(MockConnect(false, 0));
237   transport_client_socket_factory_.AddSocketDataProvider(data.data_provider());
238   // We need two connections because the pool base lets one cancelled
239   // connect job proceed for potential future use.
240   SOCKS5MockData data2(true);
241   data2.data_provider()->set_connect_data(MockConnect(false, 0));
242   transport_client_socket_factory_.AddSocketDataProvider(data2.data_provider());
243 
244   EXPECT_EQ(0, transport_socket_pool_.cancel_count());
245   EXPECT_EQ(0, transport_socket_pool_.release_count());
246   int rv = StartRequest("a", LOW);
247   EXPECT_EQ(ERR_IO_PENDING, rv);
248 
249   rv = StartRequest("a", LOW);
250   EXPECT_EQ(ERR_IO_PENDING, rv);
251 
252   pool_.CancelRequest("a", (*requests())[0]->handle());
253   pool_.CancelRequest("a", (*requests())[1]->handle());
254   EXPECT_EQ(0, transport_socket_pool_.cancel_count());
255   // Requests in the connect phase don't actually get cancelled.
256   EXPECT_EQ(0, transport_socket_pool_.release_count());
257 
258   // Now wait for the async data to reach the SOCKS connect jobs.
259   MessageLoop::current()->RunAllPending();
260 
261   EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(1));
262   EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, GetOrderOfRequest(2));
263   EXPECT_EQ(0, transport_socket_pool_.cancel_count());
264   EXPECT_EQ(0, transport_socket_pool_.release_count());
265   EXPECT_EQ(2, pool_.IdleSocketCount());
266 
267   (*requests())[0]->handle()->Reset();
268   (*requests())[1]->handle()->Reset();
269 }
270 
271 // It would be nice to also test the timeouts in SOCKSClientSocketPool.
272 
273 }  // namespace
274 
275 }  // namespace net
276