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: 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 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 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 74 virtual ~SOCKSClientSocketPoolTest() {} 75 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 81 int GetOrderOfRequest(size_t index) const { 82 return test_base_.GetOrderOfRequest(index); 83 } 84 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 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 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 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 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 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 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 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 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