• 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   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