1// Copyright (c) 2010 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/client_socket_handle.h"
6
7#include "base/compiler_specific.h"
8#include "base/metrics/histogram.h"
9#include "base/logging.h"
10#include "net/base/net_errors.h"
11#include "net/socket/client_socket_pool.h"
12#include "net/socket/client_socket_pool_histograms.h"
13
14namespace net {
15
16ClientSocketHandle::ClientSocketHandle()
17    : is_initialized_(false),
18      is_reused_(false),
19      ALLOW_THIS_IN_INITIALIZER_LIST(
20          callback_(this, &ClientSocketHandle::OnIOComplete)),
21      is_ssl_error_(false) {}
22
23ClientSocketHandle::~ClientSocketHandle() {
24  Reset();
25}
26
27void ClientSocketHandle::Reset() {
28  ResetInternal(true);
29  ResetErrorState();
30}
31
32void ClientSocketHandle::ResetInternal(bool cancel) {
33  if (group_name_.empty())  // Was Init called?
34    return;
35  if (is_initialized()) {
36    // Because of http://crbug.com/37810 we may not have a pool, but have
37    // just a raw socket.
38    socket_->NetLog().EndEvent(NetLog::TYPE_SOCKET_IN_USE, NULL);
39    if (pool_)
40      // If we've still got a socket, release it back to the ClientSocketPool so
41      // it can be deleted or reused.
42      pool_->ReleaseSocket(group_name_, release_socket(), pool_id_);
43  } else if (cancel) {
44    // If we did not get initialized yet, we've got a socket request pending.
45    // Cancel it.
46    pool_->CancelRequest(group_name_, this);
47  }
48  is_initialized_ = false;
49  group_name_.clear();
50  is_reused_ = false;
51  user_callback_ = NULL;
52  pool_ = NULL;
53  idle_time_ = base::TimeDelta();
54  init_time_ = base::TimeTicks();
55  setup_time_ = base::TimeDelta();
56  pool_id_ = -1;
57}
58
59void ClientSocketHandle::ResetErrorState() {
60  is_ssl_error_ = false;
61  ssl_error_response_info_ = HttpResponseInfo();
62  pending_http_proxy_connection_.reset();
63}
64
65LoadState ClientSocketHandle::GetLoadState() const {
66  CHECK(!is_initialized());
67  CHECK(!group_name_.empty());
68  // Because of http://crbug.com/37810  we may not have a pool, but have
69  // just a raw socket.
70  if (!pool_)
71    return LOAD_STATE_IDLE;
72  return pool_->GetLoadState(group_name_, this);
73}
74
75void ClientSocketHandle::OnIOComplete(int result) {
76  CompletionCallback* callback = user_callback_;
77  user_callback_ = NULL;
78  HandleInitCompletion(result);
79  callback->Run(result);
80}
81
82void ClientSocketHandle::HandleInitCompletion(int result) {
83  CHECK_NE(ERR_IO_PENDING, result);
84  if (result != OK) {
85    if (!socket_.get())
86      ResetInternal(false);  // Nothing to cancel since the request failed.
87    else
88      is_initialized_ = true;
89    return;
90  }
91  is_initialized_ = true;
92  CHECK_NE(-1, pool_id_) << "Pool should have set |pool_id_| to a valid value.";
93  setup_time_ = base::TimeTicks::Now() - init_time_;
94
95  ClientSocketPoolHistograms* histograms = pool_->histograms();
96  histograms->AddSocketType(reuse_type());
97  switch (reuse_type()) {
98    case ClientSocketHandle::UNUSED:
99      histograms->AddRequestTime(setup_time());
100      break;
101    case ClientSocketHandle::UNUSED_IDLE:
102      histograms->AddUnusedIdleTime(idle_time());
103      break;
104    case ClientSocketHandle::REUSED_IDLE:
105      histograms->AddReusedIdleTime(idle_time());
106      break;
107    default:
108      NOTREACHED();
109      break;
110  }
111
112  // Broadcast that the socket has been acquired.
113  // TODO(eroman): This logging is not complete, in particular set_socket() and
114  // release() socket. It ends up working though, since those methods are being
115  // used to layer sockets (and the destination sources are the same).
116  DCHECK(socket_.get());
117  socket_->NetLog().BeginEvent(
118      NetLog::TYPE_SOCKET_IN_USE,
119      make_scoped_refptr(new NetLogSourceParameter(
120          "source_dependency", requesting_source_)));
121}
122
123}  // namespace net
124