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 }
83 ResetInternal(true /* cancel */, true /* cancel_connect_job */);
84 ResetErrorState();
85 }
86
GetLoadState() const87 LoadState ClientSocketHandle::GetLoadState() const {
88 CHECK(!is_initialized());
89 CHECK(group_id_.destination().IsValid());
90 // Because of http://crbug.com/37810 we may not have a pool, but have
91 // just a raw socket.
92 if (!pool_)
93 return LOAD_STATE_IDLE;
94 return pool_->GetLoadState(group_id_, this);
95 }
96
IsPoolStalled() const97 bool ClientSocketHandle::IsPoolStalled() const {
98 if (!pool_)
99 return false;
100 return pool_->IsStalled();
101 }
102
AddHigherLayeredPool(HigherLayeredPool * higher_pool)103 void ClientSocketHandle::AddHigherLayeredPool(HigherLayeredPool* higher_pool) {
104 CHECK(higher_pool);
105 CHECK(!higher_pool_);
106 // TODO(mmenke): |pool_| should only be NULL in tests. Maybe stop doing that
107 // so this be be made into a DCHECK, and the same can be done in
108 // RemoveHigherLayeredPool?
109 if (pool_) {
110 pool_->AddHigherLayeredPool(higher_pool);
111 higher_pool_ = higher_pool;
112 }
113 }
114
RemoveHigherLayeredPool(HigherLayeredPool * higher_pool)115 void ClientSocketHandle::RemoveHigherLayeredPool(
116 HigherLayeredPool* higher_pool) {
117 CHECK(higher_pool_);
118 CHECK_EQ(higher_pool_, higher_pool);
119 if (pool_) {
120 pool_->RemoveHigherLayeredPool(higher_pool);
121 higher_pool_ = nullptr;
122 }
123 }
124
CloseIdleSocketsInGroup(const char * net_log_reason_utf8)125 void ClientSocketHandle::CloseIdleSocketsInGroup(
126 const char* net_log_reason_utf8) {
127 if (pool_)
128 pool_->CloseIdleSocketsInGroup(group_id_, net_log_reason_utf8);
129 }
130
SetAdditionalErrorState(ConnectJob * connect_job)131 void ClientSocketHandle::SetAdditionalErrorState(ConnectJob* connect_job) {
132 connection_attempts_ = connect_job->GetConnectionAttempts();
133
134 resolve_error_info_ = connect_job->GetResolveErrorInfo();
135 is_ssl_error_ = connect_job->IsSSLError();
136 ssl_cert_request_info_ = connect_job->GetCertRequestInfo();
137 }
138
OnIOComplete(int result)139 void ClientSocketHandle::OnIOComplete(int result) {
140 TRACE_EVENT0(NetTracingCategory(), "ClientSocketHandle::OnIOComplete");
141 CompletionOnceCallback callback = std::move(callback_);
142 callback_.Reset();
143 HandleInitCompletion(result);
144 std::move(callback).Run(result);
145 }
146
HandleInitCompletion(int result)147 void ClientSocketHandle::HandleInitCompletion(int result) {
148 CHECK_NE(ERR_IO_PENDING, result);
149 if (result != OK) {
150 if (!socket()) {
151 ResetInternal(false /* cancel */,
152 false /* cancel_connect_job */); // Nothing to cancel since
153 // the request failed.
154 } else {
155 set_is_initialized(true);
156 }
157 return;
158 }
159 set_is_initialized(true);
160 CHECK_NE(-1, group_generation_)
161 << "Pool should have set |group_generation_| to a valid value.";
162
163 // Broadcast that the socket has been acquired.
164 // TODO(eroman): This logging is not complete, in particular set_socket() and
165 // release() socket. It ends up working though, since those methods are being
166 // used to layer sockets (and the destination sources are the same).
167 DCHECK(socket());
168 socket()->NetLog().BeginEventReferencingSource(NetLogEventType::SOCKET_IN_USE,
169 requesting_source_);
170 }
171
ResetInternal(bool cancel,bool cancel_connect_job)172 void ClientSocketHandle::ResetInternal(bool cancel, bool cancel_connect_job) {
173 DCHECK(cancel || !cancel_connect_job);
174
175 // Was Init called?
176 if (group_id_.destination().IsValid()) {
177 // If so, we must have a pool.
178 CHECK(pool_);
179 if (is_initialized()) {
180 if (socket()) {
181 socket()->NetLog().EndEvent(NetLogEventType::SOCKET_IN_USE);
182 // Release the socket back to the ClientSocketPool so it can be
183 // deleted or reused.
184 pool_->ReleaseSocket(group_id_, PassSocket(), group_generation_);
185 } else {
186 // If the handle has been initialized, we should still have a
187 // socket.
188 NOTREACHED();
189 }
190 } else if (cancel) {
191 // If we did not get initialized yet and we have a socket
192 // request pending, cancel it.
193 pool_->CancelRequest(group_id_, this, cancel_connect_job);
194 }
195 }
196 set_is_initialized(false);
197 PassSocket();
198 group_id_ = ClientSocketPool::GroupId();
199 set_reuse_type(SocketReuseType::kUnused);
200 callback_.Reset();
201 if (higher_pool_)
202 RemoveHigherLayeredPool(higher_pool_);
203 pool_ = nullptr;
204 idle_time_ = base::TimeDelta();
205 set_connect_timing(LoadTimingInfo::ConnectTiming());
206 group_generation_ = -1;
207 }
208
ResetErrorState()209 void ClientSocketHandle::ResetErrorState() {
210 resolve_error_info_ = ResolveErrorInfo(OK);
211 is_ssl_error_ = false;
212 ssl_cert_request_info_ = nullptr;
213 }
214
215 } // namespace net
216