Home | History | Annotate | Download | only in socket
      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