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
14 namespace net {
15
ClientSocketHandle()16 ClientSocketHandle::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
~ClientSocketHandle()23 ClientSocketHandle::~ClientSocketHandle() {
24 Reset();
25 }
26
Reset()27 void ClientSocketHandle::Reset() {
28 ResetInternal(true);
29 ResetErrorState();
30 }
31
ResetInternal(bool cancel)32 void 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
ResetErrorState()59 void ClientSocketHandle::ResetErrorState() {
60 is_ssl_error_ = false;
61 ssl_error_response_info_ = HttpResponseInfo();
62 pending_http_proxy_connection_.reset();
63 }
64
GetLoadState() const65 LoadState 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
OnIOComplete(int result)75 void ClientSocketHandle::OnIOComplete(int result) {
76 CompletionCallback* callback = user_callback_;
77 user_callback_ = NULL;
78 HandleInitCompletion(result);
79 callback->Run(result);
80 }
81
HandleInitCompletion(int result)82 void 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