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