15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/socket/client_socket_handle.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/base/net_errors.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/socket/client_socket_pool.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/socket/client_socket_pool_histograms.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ClientSocketHandle::ClientSocketHandle()
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : is_initialized_(false),
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pool_(NULL),
213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      higher_pool_(NULL),
2223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      reuse_type_(ClientSocketHandle::UNUSED),
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      callback_(base::Bind(&ClientSocketHandle::OnIOComplete,
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                           base::Unretained(this))),
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_ssl_error_(false) {}
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ClientSocketHandle::~ClientSocketHandle() {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Reset();
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSocketHandle::Reset() {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResetInternal(true);
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ResetErrorState();
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSocketHandle::ResetInternal(bool cancel) {
37424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  // Was Init called?
38424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  if (!group_name_.empty()) {
39424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    // If so, we must have a pool.
40424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    CHECK(pool_);
41424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (is_initialized()) {
42424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      if (socket_) {
43424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        socket_->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE);
44424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // Release the socket back to the ClientSocketPool so it can be
45424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // deleted or reused.
46424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        pool_->ReleaseSocket(group_name_, socket_.Pass(), pool_id_);
47424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      } else {
48424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // If the handle has been initialized, we should still have a
49424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        // socket.
50424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        NOTREACHED();
51424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      }
52424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    } else if (cancel) {
53424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // If we did not get initialized yet and we have a socket
54424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      // request pending, cancel it.
55424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      pool_->CancelRequest(group_name_, this);
56424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    }
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_initialized_ = false;
59424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  socket_.reset();
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  group_name_.clear();
6123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  reuse_type_ = ClientSocketHandle::UNUSED;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  user_callback_.Reset();
633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (higher_pool_)
643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    RemoveHigherLayeredPool(higher_pool_);
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool_ = NULL;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  idle_time_ = base::TimeDelta();
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  init_time_ = base::TimeTicks();
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setup_time_ = base::TimeDelta();
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connect_timing_ = LoadTimingInfo::ConnectTiming();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool_id_ = -1;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSocketHandle::ResetErrorState() {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_ssl_error_ = false;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ssl_error_response_info_ = HttpResponseInfo();
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_http_proxy_connection_.reset();
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LoadState ClientSocketHandle::GetLoadState() const {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!is_initialized());
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!group_name_.empty());
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Because of http://crbug.com/37810  we may not have a pool, but have
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just a raw socket.
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pool_)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LOAD_STATE_IDLE;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pool_->GetLoadState(group_name_, this);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ClientSocketHandle::IsPoolStalled() const {
903551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  if (!pool_)
913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return false;
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pool_->IsStalled();
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ClientSocketHandle::AddHigherLayeredPool(HigherLayeredPool* higher_pool) {
963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(higher_pool);
973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(!higher_pool_);
983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // TODO(mmenke):  |pool_| should only be NULL in tests.  Maybe stop doing that
993551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // so this be be made into a DCHECK, and the same can be done in
1003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // RemoveHigherLayeredPool?
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pool_) {
1023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    pool_->AddHigherLayeredPool(higher_pool);
1033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    higher_pool_ = higher_pool;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ClientSocketHandle::RemoveHigherLayeredPool(
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    HigherLayeredPool* higher_pool) {
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK(higher_pool_);
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  CHECK_EQ(higher_pool_, higher_pool);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pool_) {
1123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    pool_->RemoveHigherLayeredPool(higher_pool);
1133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    higher_pool_ = NULL;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ClientSocketHandle::GetLoadTimingInfo(
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool is_reused,
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LoadTimingInfo* load_timing_info) const {
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Only return load timing information when there's a socket.
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!socket_)
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  load_timing_info->socket_log_id = socket_->NetLog().source().id;
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  load_timing_info->socket_reused = is_reused;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // No times if the socket is reused.
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (is_reused)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  load_timing_info->connect_timing = connect_timing_;
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1353551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void ClientSocketHandle::SetSocket(scoped_ptr<StreamSocket> s) {
1363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  socket_ = s.Pass();
1373551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSocketHandle::OnIOComplete(int result) {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CompletionCallback callback = user_callback_;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  user_callback_.Reset();
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandleInitCompletion(result);
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback.Run(result);
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)scoped_ptr<StreamSocket> ClientSocketHandle::PassSocket() {
1473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  return socket_.Pass();
1483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSocketHandle::HandleInitCompletion(int result) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_NE(ERR_IO_PENDING, result);
1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientSocketPoolHistograms* histograms = pool_->histograms();
1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  histograms->AddErrorCode(result);
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != OK) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!socket_.get())
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResetInternal(false);  // Nothing to cancel since the request failed.
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_initialized_ = true;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_initialized_ = true;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_NE(-1, pool_id_) << "Pool should have set |pool_id_| to a valid value.";
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setup_time_ = base::TimeTicks::Now() - init_time_;
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  histograms->AddSocketType(reuse_type());
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (reuse_type()) {
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ClientSocketHandle::UNUSED:
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      histograms->AddRequestTime(setup_time());
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ClientSocketHandle::UNUSED_IDLE:
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      histograms->AddUnusedIdleTime(idle_time());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ClientSocketHandle::REUSED_IDLE:
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      histograms->AddReusedIdleTime(idle_time());
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast that the socket has been acquired.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(eroman): This logging is not complete, in particular set_socket() and
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release() socket. It ends up working though, since those methods are being
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // used to layer sockets (and the destination sources are the same).
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(socket_.get());
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_->NetLog().BeginEvent(
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_SOCKET_IN_USE,
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      requesting_source_.ToEventParametersCallback());
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
192