1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef NET_SOCKET_WEBSOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
6 #define NET_SOCKET_WEBSOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
7 
8 #include <list>
9 #include <map>
10 #include <memory>
11 #include <set>
12 #include <string>
13 #include <utility>
14 
15 #include "base/macros.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/memory/weak_ptr.h"
18 #include "base/optional.h"
19 #include "base/time/time.h"
20 #include "base/timer/timer.h"
21 #include "net/base/net_export.h"
22 #include "net/base/proxy_server.h"
23 #include "net/log/net_log_with_source.h"
24 #include "net/socket/client_socket_pool.h"
25 #include "net/socket/connect_job.h"
26 #include "net/socket/ssl_client_socket.h"
27 
28 namespace base {
29 namespace trace_event {
30 class ProcessMemoryDump;
31 }
32 }  // namespace base
33 
34 namespace net {
35 
36 struct CommonConnectJobParams;
37 struct NetworkTrafficAnnotationTag;
38 class WebSocketTransportConnectJob;
39 
40 class NET_EXPORT_PRIVATE WebSocketTransportClientSocketPool
41     : public ClientSocketPool {
42  public:
43   WebSocketTransportClientSocketPool(
44       int max_sockets,
45       int max_sockets_per_group,
46       const ProxyServer& proxy_server,
47       const CommonConnectJobParams* common_connect_job_params);
48 
49   ~WebSocketTransportClientSocketPool() override;
50 
51   // Allow another connection to be started to the IPEndPoint that this |handle|
52   // is connected to. Used when the WebSocket handshake completes successfully.
53   // This only works if the socket is connected, however the caller does not
54   // need to explicitly check for this. Instead, ensure that dead sockets are
55   // returned to ReleaseSocket() in a timely fashion.
56   static void UnlockEndpoint(
57       ClientSocketHandle* handle,
58       WebSocketEndpointLockManager* websocket_endpoint_lock_manager);
59 
60   // ClientSocketPool implementation.
61   int RequestSocket(
62       const GroupId& group_id,
63       scoped_refptr<SocketParams> params,
64       const base::Optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
65       RequestPriority priority,
66       const SocketTag& socket_tag,
67       RespectLimits respect_limits,
68       ClientSocketHandle* handle,
69       CompletionOnceCallback callback,
70       const ProxyAuthCallback& proxy_auth_callback,
71       const NetLogWithSource& net_log) override;
72   void RequestSockets(
73       const GroupId& group_id,
74       scoped_refptr<SocketParams> params,
75       const base::Optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
76       int num_sockets,
77       const NetLogWithSource& net_log) override;
78   void SetPriority(const GroupId& group_id,
79                    ClientSocketHandle* handle,
80                    RequestPriority priority) override;
81   void CancelRequest(const GroupId& group_id,
82                      ClientSocketHandle* handle,
83                      bool cancel_connect_job) override;
84   void ReleaseSocket(const GroupId& group_id,
85                      std::unique_ptr<StreamSocket> socket,
86                      int64_t generation) override;
87   void FlushWithError(int error, const char* net_log_reason_utf8) override;
88   void CloseIdleSockets(const char* net_log_reason_utf8) override;
89   void CloseIdleSocketsInGroup(const GroupId& group_id,
90                                const char* net_log_reason_utf8) override;
91   int IdleSocketCount() const override;
92   size_t IdleSocketCountInGroup(const GroupId& group_id) const override;
93   LoadState GetLoadState(const GroupId& group_id,
94                          const ClientSocketHandle* handle) const override;
95   base::Value GetInfoAsValue(const std::string& name,
96                              const std::string& type) const override;
97   void DumpMemoryStats(
98       base::trace_event::ProcessMemoryDump* pmd,
99       const std::string& parent_dump_absolute_name) const override;
100 
101   // HigherLayeredPool implementation.
102   bool IsStalled() const override;
103   void AddHigherLayeredPool(HigherLayeredPool* higher_pool) override;
104   void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) override;
105 
106  private:
107   class ConnectJobDelegate : public ConnectJob::Delegate {
108    public:
109     ConnectJobDelegate(WebSocketTransportClientSocketPool* owner,
110                        CompletionOnceCallback callback,
111                        ClientSocketHandle* socket_handle,
112                        const NetLogWithSource& request_net_log);
113     ~ConnectJobDelegate() override;
114 
115     // ConnectJob::Delegate implementation
116     void OnConnectJobComplete(int result, ConnectJob* job) override;
117     void OnNeedsProxyAuth(const HttpResponseInfo& response,
118                           HttpAuthController* auth_controller,
119                           base::OnceClosure restart_with_auth_callback,
120                           ConnectJob* job) override;
121 
122     // Calls Connect() on |connect_job|, and takes ownership. Returns Connect's
123     // return value.
124     int Connect(std::unique_ptr<ConnectJob> connect_job);
125 
release_callback()126     CompletionOnceCallback release_callback() { return std::move(callback_); }
connect_job()127     ConnectJob* connect_job() { return connect_job_.get(); }
socket_handle()128     ClientSocketHandle* socket_handle() { return socket_handle_; }
129 
request_net_log()130     const NetLogWithSource& request_net_log() { return request_net_log_; }
131     const NetLogWithSource& connect_job_net_log();
132 
133    private:
134     WebSocketTransportClientSocketPool* owner_;
135 
136     CompletionOnceCallback callback_;
137     std::unique_ptr<ConnectJob> connect_job_;
138     ClientSocketHandle* const socket_handle_;
139     const NetLogWithSource request_net_log_;
140 
141     DISALLOW_COPY_AND_ASSIGN(ConnectJobDelegate);
142   };
143 
144   // Store the arguments from a call to RequestSocket() that has stalled so we
145   // can replay it when there are available socket slots.
146   struct StalledRequest {
147     StalledRequest(
148         const GroupId& group_id,
149         const scoped_refptr<SocketParams>& params,
150         const base::Optional<NetworkTrafficAnnotationTag>& proxy_annotation_tag,
151         RequestPriority priority,
152         ClientSocketHandle* handle,
153         CompletionOnceCallback callback,
154         const ProxyAuthCallback& proxy_auth_callback,
155         const NetLogWithSource& net_log);
156     StalledRequest(StalledRequest&& other);
157     ~StalledRequest();
158 
159     const GroupId group_id;
160     const scoped_refptr<SocketParams> params;
161     const base::Optional<NetworkTrafficAnnotationTag> proxy_annotation_tag;
162     const RequestPriority priority;
163     ClientSocketHandle* const handle;
164     CompletionOnceCallback callback;
165     ProxyAuthCallback proxy_auth_callback;
166     const NetLogWithSource net_log;
167   };
168 
169   typedef std::map<const ClientSocketHandle*,
170                    std::unique_ptr<ConnectJobDelegate>>
171       PendingConnectsMap;
172   // This is a list so that we can remove requests from the middle, and also
173   // so that iterators are not invalidated unless the corresponding request is
174   // removed.
175   typedef std::list<StalledRequest> StalledRequestQueue;
176   typedef std::map<const ClientSocketHandle*, StalledRequestQueue::iterator>
177       StalledRequestMap;
178 
179   // Tries to hand out the socket connected by |job|. |result| must be (async)
180   // result of WebSocketTransportConnectJob::Connect(). Returns true iff it has
181   // handed out a socket.
182   bool TryHandOutSocket(int result, ConnectJobDelegate* connect_job_delegate);
183   void OnConnectJobComplete(int result,
184                             ConnectJobDelegate* connect_job_delegate);
185   void InvokeUserCallbackLater(ClientSocketHandle* handle,
186                                CompletionOnceCallback callback,
187                                int rv);
188   void InvokeUserCallback(ClientSocketHandle* handle,
189                           CompletionOnceCallback callback,
190                           int rv);
191   bool ReachedMaxSocketsLimit() const;
192   void HandOutSocket(std::unique_ptr<StreamSocket> socket,
193                      const LoadTimingInfo::ConnectTiming& connect_timing,
194                      ClientSocketHandle* handle,
195                      const NetLogWithSource& net_log);
196   void AddJob(ClientSocketHandle* handle,
197               std::unique_ptr<ConnectJobDelegate> delegate);
198   bool DeleteJob(ClientSocketHandle* handle);
199   const ConnectJob* LookupConnectJob(const ClientSocketHandle* handle) const;
200   void ActivateStalledRequest();
201   bool DeleteStalledRequest(ClientSocketHandle* handle);
202 
203   const ProxyServer proxy_server_;
204   const CommonConnectJobParams* const common_connect_job_params_;
205   std::set<const ClientSocketHandle*> pending_callbacks_;
206   PendingConnectsMap pending_connects_;
207   StalledRequestQueue stalled_request_queue_;
208   StalledRequestMap stalled_request_map_;
209   const int max_sockets_;
210   int handed_out_socket_count_;
211   bool flushing_;
212 
213   base::WeakPtrFactory<WebSocketTransportClientSocketPool> weak_factory_{this};
214 
215   DISALLOW_COPY_AND_ASSIGN(WebSocketTransportClientSocketPool);
216 };
217 
218 }  // namespace net
219 
220 #endif  // NET_SOCKET_WEBSOCKET_TRANSPORT_CLIENT_SOCKET_POOL_H_
221