1 // Copyright 2012 The Chromium Authors
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 <utility>
8
9 #include "base/check_op.h"
10 #include "base/compiler_specific.h"
11 #include "base/functional/bind.h"
12 #include "base/functional/callback_helpers.h"
13 #include "base/notreached.h"
14 #include "net/base/net_errors.h"
15 #include "net/base/trace_constants.h"
16 #include "net/base/tracing.h"
17 #include "net/log/net_log_event_type.h"
18 #include "net/socket/client_socket_pool.h"
19 #include "net/socket/connect_job.h"
20
21 namespace net {
22
ClientSocketHandle()23 ClientSocketHandle::ClientSocketHandle()
24 : resolve_error_info_(ResolveErrorInfo(OK)) {}
25
~ClientSocketHandle()26 ClientSocketHandle::~ClientSocketHandle() {
27 Reset();
28 }
29
Init(const ClientSocketPool::GroupId & group_id,scoped_refptr<ClientSocketPool::SocketParams> socket_params,const absl::optional<NetworkTrafficAnnotationTag> & proxy_annotation_tag,RequestPriority priority,const SocketTag & socket_tag,ClientSocketPool::RespectLimits respect_limits,CompletionOnceCallback callback,const ClientSocketPool::ProxyAuthCallback & proxy_auth_callback,ClientSocketPool * pool,const NetLogWithSource & net_log)30 int ClientSocketHandle::Init(
31 const ClientSocketPool::GroupId& group_id,
32 scoped_refptr<ClientSocketPool::SocketParams> socket_params,
33 const absl::optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
34 RequestPriority priority,
35 const SocketTag& socket_tag,
36 ClientSocketPool::RespectLimits respect_limits,
37 CompletionOnceCallback callback,
38 const ClientSocketPool::ProxyAuthCallback& proxy_auth_callback,
39 ClientSocketPool* pool,
40 const NetLogWithSource& net_log) {
41 requesting_source_ = net_log.source();
42
43 CHECK(group_id.destination().IsValid());
44 ResetInternal(true /* cancel */, false /* cancel_connect_job */);
45 ResetErrorState();
46 pool_ = pool;
47 group_id_ = group_id;
48 CompletionOnceCallback io_complete_callback =
49 base::BindOnce(&ClientSocketHandle::OnIOComplete, base::Unretained(this));
50 int rv = pool_->RequestSocket(
51 group_id, std::move(socket_params), proxy_annotation_tag, priority,
52 socket_tag, respect_limits, this, std::move(io_complete_callback),
53 proxy_auth_callback, net_log);
54 if (rv == ERR_IO_PENDING) {
55 callback_ = std::move(callback);
56 } else {
57 HandleInitCompletion(rv);
58 }
59 return rv;
60 }
61
SetPriority(RequestPriority priority)62 void ClientSocketHandle::SetPriority(RequestPriority priority) {
63 if (socket_) {
64 // The priority of the handle is no longer relevant to the socket pool;
65 // just return.
66 return;
67 }
68
69 if (pool_)
70 pool_->SetPriority(group_id_, this, priority);
71 }
72
Reset()73 void ClientSocketHandle::Reset() {
74 ResetInternal(true /* cancel */, false /* cancel_connect_job */);
75 ResetErrorState();
76 }
77
ResetAndCloseSocket()78 void ClientSocketHandle::ResetAndCloseSocket() {
79 if (is_initialized() && socket_)
80 socket_->Disconnect();
81 ResetInternal(true /* cancel */, true /* cancel_connect_job */);
82 ResetErrorState();
83 }
84
GetLoadState() const85 LoadState ClientSocketHandle::GetLoadState() const {
86 CHECK(!is_initialized());
87 CHECK(group_id_.destination().IsValid());
88 // Because of http://crbug.com/37810 we may not have a pool, but have
89 // just a raw socket.
90 if (!pool_)
91 return LOAD_STATE_IDLE;
92 return pool_->GetLoadState(group_id_, this);
93 }
94
IsPoolStalled() const95 bool ClientSocketHandle::IsPoolStalled() const {
96 if (!pool_)
97 return false;
98 return pool_->IsStalled();
99 }
100
AddHigherLayeredPool(HigherLayeredPool * higher_pool)101 void ClientSocketHandle::AddHigherLayeredPool(HigherLayeredPool* higher_pool) {
102 CHECK(higher_pool);
103 CHECK(!higher_pool_);
104 // TODO(mmenke): |pool_| should only be NULL in tests. Maybe stop doing that
105 // so this be be made into a DCHECK, and the same can be done in
106 // RemoveHigherLayeredPool?
107 if (pool_) {
108 pool_->AddHigherLayeredPool(higher_pool);
109 higher_pool_ = higher_pool;
110 }
111 }
112
RemoveHigherLayeredPool(HigherLayeredPool * higher_pool)113 void ClientSocketHandle::RemoveHigherLayeredPool(
114 HigherLayeredPool* higher_pool) {
115 CHECK(higher_pool_);
116 CHECK_EQ(higher_pool_, higher_pool);
117 if (pool_) {
118 pool_->RemoveHigherLayeredPool(higher_pool);
119 higher_pool_ = nullptr;
120 }
121 }
122
CloseIdleSocketsInGroup(const char * net_log_reason_utf8)123 void ClientSocketHandle::CloseIdleSocketsInGroup(
124 const char* net_log_reason_utf8) {
125 if (pool_)
126 pool_->CloseIdleSocketsInGroup(group_id_, net_log_reason_utf8);
127 }
128
GetLoadTimingInfo(bool is_reused,LoadTimingInfo * load_timing_info) const129 bool ClientSocketHandle::GetLoadTimingInfo(
130 bool is_reused,
131 LoadTimingInfo* load_timing_info) const {
132 if (socket_) {
133 load_timing_info->socket_log_id = socket_->NetLog().source().id;
134 } else {
135 // Only return load timing information when there's a socket.
136 return false;
137 }
138
139 load_timing_info->socket_reused = is_reused;
140
141 // No times if the socket is reused.
142 if (is_reused)
143 return true;
144
145 load_timing_info->connect_timing = connect_timing_;
146 return true;
147 }
148
SetSocket(std::unique_ptr<StreamSocket> s)149 void ClientSocketHandle::SetSocket(std::unique_ptr<StreamSocket> s) {
150 socket_ = std::move(s);
151 }
152
SetAdditionalErrorState(ConnectJob * connect_job)153 void ClientSocketHandle::SetAdditionalErrorState(ConnectJob* connect_job) {
154 connection_attempts_ = connect_job->GetConnectionAttempts();
155
156 resolve_error_info_ = connect_job->GetResolveErrorInfo();
157 is_ssl_error_ = connect_job->IsSSLError();
158 ssl_cert_request_info_ = connect_job->GetCertRequestInfo();
159 }
160
PassSocket()161 std::unique_ptr<StreamSocket> ClientSocketHandle::PassSocket() {
162 return std::move(socket_);
163 }
164
OnIOComplete(int result)165 void ClientSocketHandle::OnIOComplete(int result) {
166 TRACE_EVENT0(NetTracingCategory(), "ClientSocketHandle::OnIOComplete");
167 CompletionOnceCallback callback = std::move(callback_);
168 callback_.Reset();
169 HandleInitCompletion(result);
170 std::move(callback).Run(result);
171 }
172
HandleInitCompletion(int result)173 void ClientSocketHandle::HandleInitCompletion(int result) {
174 CHECK_NE(ERR_IO_PENDING, result);
175 if (result != OK) {
176 if (!socket_.get())
177 ResetInternal(false /* cancel */,
178 false /* cancel_connect_job */); // Nothing to cancel since
179 // the request failed.
180 else
181 is_initialized_ = true;
182 return;
183 }
184 is_initialized_ = true;
185 CHECK_NE(-1, group_generation_)
186 << "Pool should have set |group_generation_| to a valid value.";
187
188 // Broadcast that the socket has been acquired.
189 // TODO(eroman): This logging is not complete, in particular set_socket() and
190 // release() socket. It ends up working though, since those methods are being
191 // used to layer sockets (and the destination sources are the same).
192 DCHECK(socket_.get());
193 socket_->NetLog().BeginEventReferencingSource(NetLogEventType::SOCKET_IN_USE,
194 requesting_source_);
195 }
196
ResetInternal(bool cancel,bool cancel_connect_job)197 void ClientSocketHandle::ResetInternal(bool cancel, bool cancel_connect_job) {
198 DCHECK(cancel || !cancel_connect_job);
199
200 // Was Init called?
201 if (group_id_.destination().IsValid()) {
202 // If so, we must have a pool.
203 CHECK(pool_);
204 if (is_initialized()) {
205 if (socket_) {
206 socket_->NetLog().EndEvent(NetLogEventType::SOCKET_IN_USE);
207 // Release the socket back to the ClientSocketPool so it can be
208 // deleted or reused.
209 pool_->ReleaseSocket(group_id_, std::move(socket_), group_generation_);
210 } else {
211 // If the handle has been initialized, we should still have a
212 // socket.
213 NOTREACHED();
214 }
215 } else if (cancel) {
216 // If we did not get initialized yet and we have a socket
217 // request pending, cancel it.
218 pool_->CancelRequest(group_id_, this, cancel_connect_job);
219 }
220 }
221 is_initialized_ = false;
222 socket_.reset();
223 group_id_ = ClientSocketPool::GroupId();
224 reuse_type_ = ClientSocketHandle::UNUSED;
225 callback_.Reset();
226 if (higher_pool_)
227 RemoveHigherLayeredPool(higher_pool_);
228 pool_ = nullptr;
229 idle_time_ = base::TimeDelta();
230 connect_timing_ = LoadTimingInfo::ConnectTiming();
231 group_generation_ = -1;
232 }
233
ResetErrorState()234 void ClientSocketHandle::ResetErrorState() {
235 resolve_error_info_ = ResolveErrorInfo(OK);
236 is_ssl_error_ = false;
237 ssl_cert_request_info_ = nullptr;
238 }
239
240 } // namespace net
241