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),
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      layered_pool_(NULL),
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_reused_(false),
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) {
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (group_name_.empty())  // Was Init called?
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (is_initialized()) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Because of http://crbug.com/37810 we may not have a pool, but have
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // just a raw socket.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    socket_->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (pool_)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // If we've still got a socket, release it back to the ClientSocketPool so
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // it can be deleted or reused.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      pool_->ReleaseSocket(group_name_, release_socket(), pool_id_);
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (cancel) {
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // If we did not get initialized yet, we've got a socket request pending.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Cancel it.
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pool_->CancelRequest(group_name_, this);
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_initialized_ = false;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  group_name_.clear();
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_reused_ = false;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  user_callback_.Reset();
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (layered_pool_) {
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pool_->RemoveLayeredPool(layered_pool_);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    layered_pool_ = NULL;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool_ = NULL;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  idle_time_ = base::TimeDelta();
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  init_time_ = base::TimeTicks();
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setup_time_ = base::TimeDelta();
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  connect_timing_ = LoadTimingInfo::ConnectTiming();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pool_id_ = -1;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSocketHandle::ResetErrorState() {
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_ssl_error_ = false;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ssl_error_response_info_ = HttpResponseInfo();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pending_http_proxy_connection_.reset();
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LoadState ClientSocketHandle::GetLoadState() const {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!is_initialized());
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!group_name_.empty());
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Because of http://crbug.com/37810  we may not have a pool, but have
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // just a raw socket.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!pool_)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return LOAD_STATE_IDLE;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pool_->GetLoadState(group_name_, this);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ClientSocketHandle::IsPoolStalled() const {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return pool_->IsStalled();
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSocketHandle::AddLayeredPool(LayeredPool* layered_pool) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(layered_pool);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(!layered_pool_);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pool_) {
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pool_->AddLayeredPool(layered_pool);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    layered_pool_ = layered_pool;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSocketHandle::RemoveLayeredPool(LayeredPool* layered_pool) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(layered_pool);
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK(layered_pool_);
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pool_) {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pool_->RemoveLayeredPool(layered_pool);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    layered_pool_ = NULL;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ClientSocketHandle::GetLoadTimingInfo(
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool is_reused,
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    LoadTimingInfo* load_timing_info) const {
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Only return load timing information when there's a socket.
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!socket_)
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  load_timing_info->socket_log_id = socket_->NetLog().source().id;
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  load_timing_info->socket_reused = is_reused;
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // No times if the socket is reused.
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (is_reused)
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  load_timing_info->connect_timing = connect_timing_;
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSocketHandle::OnIOComplete(int result) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CompletionCallback callback = user_callback_;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  user_callback_.Reset();
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HandleInitCompletion(result);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback.Run(result);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ClientSocketHandle::HandleInitCompletion(int result) {
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_NE(ERR_IO_PENDING, result);
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ClientSocketPoolHistograms* histograms = pool_->histograms();
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  histograms->AddErrorCode(result);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (result != OK) {
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!socket_.get())
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ResetInternal(false);  // Nothing to cancel since the request failed.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      is_initialized_ = true;
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  is_initialized_ = true;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CHECK_NE(-1, pool_id_) << "Pool should have set |pool_id_| to a valid value.";
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  setup_time_ = base::TimeTicks::Now() - init_time_;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  histograms->AddSocketType(reuse_type());
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  switch (reuse_type()) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ClientSocketHandle::UNUSED:
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      histograms->AddRequestTime(setup_time());
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ClientSocketHandle::UNUSED_IDLE:
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      histograms->AddUnusedIdleTime(idle_time());
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case ClientSocketHandle::REUSED_IDLE:
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      histograms->AddReusedIdleTime(idle_time());
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      break;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Broadcast that the socket has been acquired.
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // TODO(eroman): This logging is not complete, in particular set_socket() and
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // release() socket. It ends up working though, since those methods are being
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // used to layer sockets (and the destination sources are the same).
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(socket_.get());
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  socket_->NetLog().BeginEvent(
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NetLog::TYPE_SOCKET_IN_USE,
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      requesting_source_.ToEventParametersCallback());
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace net
173