xref: /aosp_15_r20/external/cronet/net/socket/client_socket_handle.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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