Home | History | Annotate | Download | only in socket
      1 // Copyright (c) 2013 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/tcp_client_socket.h"
      6 
      7 #include "base/callback_helpers.h"
      8 #include "base/logging.h"
      9 #include "net/base/io_buffer.h"
     10 #include "net/base/ip_endpoint.h"
     11 #include "net/base/net_errors.h"
     12 #include "net/base/net_util.h"
     13 
     14 namespace net {
     15 
     16 TCPClientSocket::TCPClientSocket(const AddressList& addresses,
     17                                  net::NetLog* net_log,
     18                                  const net::NetLog::Source& source)
     19     : socket_(new TCPSocket(net_log, source)),
     20       addresses_(addresses),
     21       current_address_index_(-1),
     22       next_connect_state_(CONNECT_STATE_NONE),
     23       previously_disconnected_(false) {
     24 }
     25 
     26 TCPClientSocket::TCPClientSocket(scoped_ptr<TCPSocket> connected_socket,
     27                                  const IPEndPoint& peer_address)
     28     : socket_(connected_socket.Pass()),
     29       addresses_(AddressList(peer_address)),
     30       current_address_index_(0),
     31       next_connect_state_(CONNECT_STATE_NONE),
     32       previously_disconnected_(false) {
     33   DCHECK(socket_);
     34 
     35   socket_->SetDefaultOptionsForClient();
     36   use_history_.set_was_ever_connected();
     37 }
     38 
     39 TCPClientSocket::~TCPClientSocket() {
     40 }
     41 
     42 int TCPClientSocket::Bind(const IPEndPoint& address) {
     43   if (current_address_index_ >= 0 || bind_address_) {
     44     // Cannot bind the socket if we are already connected or connecting.
     45     NOTREACHED();
     46     return ERR_UNEXPECTED;
     47   }
     48 
     49   int result = OK;
     50   if (!socket_->IsValid()) {
     51     result = OpenSocket(address.GetFamily());
     52     if (result != OK)
     53       return result;
     54   }
     55 
     56   result = socket_->Bind(address);
     57   if (result != OK)
     58     return result;
     59 
     60   bind_address_.reset(new IPEndPoint(address));
     61   return OK;
     62 }
     63 
     64 int TCPClientSocket::Connect(const CompletionCallback& callback) {
     65   DCHECK(!callback.is_null());
     66 
     67   // If connecting or already connected, then just return OK.
     68   if (socket_->IsValid() && current_address_index_ >= 0)
     69     return OK;
     70 
     71   socket_->StartLoggingMultipleConnectAttempts(addresses_);
     72 
     73   // We will try to connect to each address in addresses_. Start with the
     74   // first one in the list.
     75   next_connect_state_ = CONNECT_STATE_CONNECT;
     76   current_address_index_ = 0;
     77 
     78   int rv = DoConnectLoop(OK);
     79   if (rv == ERR_IO_PENDING) {
     80     connect_callback_ = callback;
     81   } else {
     82     socket_->EndLoggingMultipleConnectAttempts(rv);
     83   }
     84 
     85   return rv;
     86 }
     87 
     88 int TCPClientSocket::DoConnectLoop(int result) {
     89   DCHECK_NE(next_connect_state_, CONNECT_STATE_NONE);
     90 
     91   int rv = result;
     92   do {
     93     ConnectState state = next_connect_state_;
     94     next_connect_state_ = CONNECT_STATE_NONE;
     95     switch (state) {
     96       case CONNECT_STATE_CONNECT:
     97         DCHECK_EQ(OK, rv);
     98         rv = DoConnect();
     99         break;
    100       case CONNECT_STATE_CONNECT_COMPLETE:
    101         rv = DoConnectComplete(rv);
    102         break;
    103       default:
    104         NOTREACHED() << "bad state " << state;
    105         rv = ERR_UNEXPECTED;
    106         break;
    107     }
    108   } while (rv != ERR_IO_PENDING && next_connect_state_ != CONNECT_STATE_NONE);
    109 
    110   return rv;
    111 }
    112 
    113 int TCPClientSocket::DoConnect() {
    114   DCHECK_GE(current_address_index_, 0);
    115   DCHECK_LT(current_address_index_, static_cast<int>(addresses_.size()));
    116 
    117   const IPEndPoint& endpoint = addresses_[current_address_index_];
    118 
    119   if (previously_disconnected_) {
    120     use_history_.Reset();
    121     previously_disconnected_ = false;
    122   }
    123 
    124   next_connect_state_ = CONNECT_STATE_CONNECT_COMPLETE;
    125 
    126   if (socket_->IsValid()) {
    127     DCHECK(bind_address_);
    128   } else {
    129     int result = OpenSocket(endpoint.GetFamily());
    130     if (result != OK)
    131       return result;
    132 
    133     if (bind_address_) {
    134       result = socket_->Bind(*bind_address_);
    135       if (result != OK) {
    136         socket_->Close();
    137         return result;
    138       }
    139     }
    140   }
    141 
    142   // |socket_| is owned by this class and the callback won't be run once
    143   // |socket_| is gone. Therefore, it is safe to use base::Unretained() here.
    144   return socket_->Connect(endpoint,
    145                           base::Bind(&TCPClientSocket::DidCompleteConnect,
    146                                      base::Unretained(this)));
    147 }
    148 
    149 int TCPClientSocket::DoConnectComplete(int result) {
    150   if (result == OK) {
    151     use_history_.set_was_ever_connected();
    152     return OK;  // Done!
    153   }
    154 
    155   // Close whatever partially connected socket we currently have.
    156   DoDisconnect();
    157 
    158   // Try to fall back to the next address in the list.
    159   if (current_address_index_ + 1 < static_cast<int>(addresses_.size())) {
    160     next_connect_state_ = CONNECT_STATE_CONNECT;
    161     ++current_address_index_;
    162     return OK;
    163   }
    164 
    165   // Otherwise there is nothing to fall back to, so give up.
    166   return result;
    167 }
    168 
    169 void TCPClientSocket::Disconnect() {
    170   DoDisconnect();
    171   current_address_index_ = -1;
    172   bind_address_.reset();
    173 }
    174 
    175 void TCPClientSocket::DoDisconnect() {
    176   // If connecting or already connected, record that the socket has been
    177   // disconnected.
    178   previously_disconnected_ = socket_->IsValid() && current_address_index_ >= 0;
    179   socket_->Close();
    180 }
    181 
    182 bool TCPClientSocket::IsConnected() const {
    183   return socket_->IsConnected();
    184 }
    185 
    186 bool TCPClientSocket::IsConnectedAndIdle() const {
    187   return socket_->IsConnectedAndIdle();
    188 }
    189 
    190 int TCPClientSocket::GetPeerAddress(IPEndPoint* address) const {
    191   return socket_->GetPeerAddress(address);
    192 }
    193 
    194 int TCPClientSocket::GetLocalAddress(IPEndPoint* address) const {
    195   DCHECK(address);
    196 
    197   if (!socket_->IsValid()) {
    198     if (bind_address_) {
    199       *address = *bind_address_;
    200       return OK;
    201     }
    202     return ERR_SOCKET_NOT_CONNECTED;
    203   }
    204 
    205   return socket_->GetLocalAddress(address);
    206 }
    207 
    208 const BoundNetLog& TCPClientSocket::NetLog() const {
    209   return socket_->net_log();
    210 }
    211 
    212 void TCPClientSocket::SetSubresourceSpeculation() {
    213   use_history_.set_subresource_speculation();
    214 }
    215 
    216 void TCPClientSocket::SetOmniboxSpeculation() {
    217   use_history_.set_omnibox_speculation();
    218 }
    219 
    220 bool TCPClientSocket::WasEverUsed() const {
    221   return use_history_.was_used_to_convey_data();
    222 }
    223 
    224 bool TCPClientSocket::UsingTCPFastOpen() const {
    225   return socket_->UsingTCPFastOpen();
    226 }
    227 
    228 bool TCPClientSocket::WasNpnNegotiated() const {
    229   return false;
    230 }
    231 
    232 NextProto TCPClientSocket::GetNegotiatedProtocol() const {
    233   return kProtoUnknown;
    234 }
    235 
    236 bool TCPClientSocket::GetSSLInfo(SSLInfo* ssl_info) {
    237   return false;
    238 }
    239 
    240 int TCPClientSocket::Read(IOBuffer* buf,
    241                           int buf_len,
    242                           const CompletionCallback& callback) {
    243   DCHECK(!callback.is_null());
    244 
    245   // |socket_| is owned by this class and the callback won't be run once
    246   // |socket_| is gone. Therefore, it is safe to use base::Unretained() here.
    247   CompletionCallback read_callback = base::Bind(
    248       &TCPClientSocket::DidCompleteReadWrite, base::Unretained(this), callback);
    249   int result = socket_->Read(buf, buf_len, read_callback);
    250   if (result > 0)
    251     use_history_.set_was_used_to_convey_data();
    252 
    253   return result;
    254 }
    255 
    256 int TCPClientSocket::Write(IOBuffer* buf,
    257                            int buf_len,
    258                            const CompletionCallback& callback) {
    259   DCHECK(!callback.is_null());
    260 
    261   // |socket_| is owned by this class and the callback won't be run once
    262   // |socket_| is gone. Therefore, it is safe to use base::Unretained() here.
    263   CompletionCallback write_callback = base::Bind(
    264       &TCPClientSocket::DidCompleteReadWrite, base::Unretained(this), callback);
    265   int result = socket_->Write(buf, buf_len, write_callback);
    266   if (result > 0)
    267     use_history_.set_was_used_to_convey_data();
    268 
    269   return result;
    270 }
    271 
    272 int TCPClientSocket::SetReceiveBufferSize(int32 size) {
    273   return socket_->SetReceiveBufferSize(size);
    274 }
    275 
    276 int TCPClientSocket::SetSendBufferSize(int32 size) {
    277     return socket_->SetSendBufferSize(size);
    278 }
    279 
    280 bool TCPClientSocket::SetKeepAlive(bool enable, int delay) {
    281   return socket_->SetKeepAlive(enable, delay);
    282 }
    283 
    284 bool TCPClientSocket::SetNoDelay(bool no_delay) {
    285   return socket_->SetNoDelay(no_delay);
    286 }
    287 
    288 void TCPClientSocket::DidCompleteConnect(int result) {
    289   DCHECK_EQ(next_connect_state_, CONNECT_STATE_CONNECT_COMPLETE);
    290   DCHECK_NE(result, ERR_IO_PENDING);
    291   DCHECK(!connect_callback_.is_null());
    292 
    293   result = DoConnectLoop(result);
    294   if (result != ERR_IO_PENDING) {
    295     socket_->EndLoggingMultipleConnectAttempts(result);
    296     base::ResetAndReturn(&connect_callback_).Run(result);
    297   }
    298 }
    299 
    300 void TCPClientSocket::DidCompleteReadWrite(const CompletionCallback& callback,
    301                                            int result) {
    302   if (result > 0)
    303     use_history_.set_was_used_to_convey_data();
    304 
    305   callback.Run(result);
    306 }
    307 
    308 int TCPClientSocket::OpenSocket(AddressFamily family) {
    309   DCHECK(!socket_->IsValid());
    310 
    311   int result = socket_->Open(family);
    312   if (result != OK)
    313     return result;
    314 
    315   socket_->SetDefaultOptionsForClient();
    316 
    317   return OK;
    318 }
    319 
    320 }  // namespace net
    321