• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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