summaryrefslogtreecommitdiffstats
path: root/net/socket/client_socket_pool_base.h
diff options
context:
space:
mode:
Diffstat (limited to 'net/socket/client_socket_pool_base.h')
-rw-r--r--net/socket/client_socket_pool_base.h257
1 files changed, 214 insertions, 43 deletions
diff --git a/net/socket/client_socket_pool_base.h b/net/socket/client_socket_pool_base.h
index 4ae96f8..bae88b7 100644
--- a/net/socket/client_socket_pool_base.h
+++ b/net/socket/client_socket_pool_base.h
@@ -1,7 +1,24 @@
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-
+//
+// A ClientSocketPoolBase is used to restrict the number of sockets open at
+// a time. It also maintains a list of idle persistent sockets for reuse.
+// Subclasses of ClientSocketPool should compose ClientSocketPoolBase to handle
+// the core logic of (1) restricting the number of active (connected or
+// connecting) sockets per "group" (generally speaking, the hostname), (2)
+// maintaining a per-group list of idle, persistent sockets for reuse, and (3)
+// limiting the total number of active sockets in the system.
+//
+// ClientSocketPoolBase abstracts socket connection details behind ConnectJob,
+// ConnectJobFactory, and SocketParams. When a socket "slot" becomes available,
+// the ClientSocketPoolBase will ask the ConnectJobFactory to create a
+// ConnectJob with a SocketParams. Subclasses of ClientSocketPool should
+// implement their socket specific connection by subclassing ConnectJob and
+// implementing ConnectJob::ConnectInternal(). They can control the parameters
+// passed to each new ConnectJob instance via their ConnectJobFactory subclass
+// and templated SocketParams parameter.
+//
#ifndef NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_
#define NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_
@@ -16,16 +33,15 @@
#include "base/timer.h"
#include "net/base/address_list.h"
#include "net/base/completion_callback.h"
-#include "net/base/host_resolver.h"
#include "net/base/load_log.h"
#include "net/base/load_states.h"
+#include "net/base/net_errors.h"
#include "net/socket/client_socket.h"
#include "net/socket/client_socket_pool.h"
namespace net {
class ClientSocketHandle;
-class ClientSocketPoolBase;
// ConnectJob provides an abstract interface for "connecting" a socket.
// The connection may involve host resolution, tcp connection, ssl connection,
@@ -93,37 +109,39 @@ class ConnectJob {
DISALLOW_COPY_AND_ASSIGN(ConnectJob);
};
-// A ClientSocketPoolBase is used to restrict the number of sockets open at
-// a time. It also maintains a list of idle persistent sockets.
-//
-class ClientSocketPoolBase
- : public base::RefCounted<ClientSocketPoolBase>,
+namespace internal {
+
+// ClientSocketPoolBaseHelper is an internal class that implements almost all
+// the functionality from ClientSocketPoolBase without using templates.
+// ClientSocketPoolBase adds templated definitions built on top of
+// ClientSocketPoolBaseHelper. This class is not for external use, please use
+// ClientSocketPoolBase instead.
+class ClientSocketPoolBaseHelper
+ : public base::RefCounted<ClientSocketPoolBaseHelper>,
public ConnectJob::Delegate {
public:
- // A Request is allocated per call to RequestSocket that results in
- // ERR_IO_PENDING.
- struct Request {
- // HostResolver::RequestInfo has no default constructor, so fudge something.
- Request()
- : handle(NULL),
- callback(NULL),
- priority(0),
- resolve_info(std::string(), 0) {}
-
+ class Request {
+ public:
Request(ClientSocketHandle* handle,
CompletionCallback* callback,
int priority,
- const HostResolver::RequestInfo& resolve_info,
LoadLog* load_log)
- : load_log(load_log), handle(handle), callback(callback),
- priority(priority), resolve_info(resolve_info) {
- }
+ : handle_(handle), callback_(callback), priority_(priority) {}
+
+ virtual ~Request() {}
- scoped_refptr<LoadLog> load_log;
- ClientSocketHandle* handle;
- CompletionCallback* callback;
- int priority;
- HostResolver::RequestInfo resolve_info;
+ ClientSocketHandle* handle() const { return handle_; }
+ CompletionCallback* callback() const { return callback_; }
+ int priority() const { return priority_; }
+ LoadLog* load_log() const { return load_log_.get(); }
+
+ private:
+ ClientSocketHandle* const handle_;
+ CompletionCallback* const callback_;
+ const int priority_;
+ const scoped_refptr<LoadLog> load_log_;
+
+ DISALLOW_COPY_AND_ASSIGN(Request);
};
class ConnectJobFactory {
@@ -140,36 +158,42 @@ class ClientSocketPoolBase
DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
};
- ClientSocketPoolBase(int max_sockets,
- int max_sockets_per_group,
- ConnectJobFactory* connect_job_factory);
+ ClientSocketPoolBaseHelper(int max_sockets,
+ int max_sockets_per_group,
+ ConnectJobFactory* connect_job_factory);
- ~ClientSocketPoolBase();
+ ~ClientSocketPoolBaseHelper();
- int RequestSocket(const std::string& group_name,
- const HostResolver::RequestInfo& resolve_info,
- int priority,
- ClientSocketHandle* handle,
- CompletionCallback* callback,
- LoadLog* load_log);
+ // See ClientSocketPool::RequestSocket for documentation on this function.
+ // Note that |request| must be heap allocated. If ERR_IO_PENDING is returned,
+ // then ClientSocketPoolBaseHelper takes ownership of |request|.
+ int RequestSocket(const std::string& group_name, const Request* request);
+ // See ClientSocketPool::CancelRequest for documentation on this function.
void CancelRequest(const std::string& group_name,
const ClientSocketHandle* handle);
+ // See ClientSocketPool::ReleaseSocket for documentation on this function.
void ReleaseSocket(const std::string& group_name,
ClientSocket* socket);
+ // See ClientSocketPool::CloseIdleSockets for documentation on this function.
void CloseIdleSockets();
+ // See ClientSocketPool::IdleSocketCount() for documentation on this function.
int idle_socket_count() const {
return idle_socket_count_;
}
+ // See ClientSocketPool::IdleSocketCountInGroup() for documentation on this
+ // function.
int IdleSocketCountInGroup(const std::string& group_name) const;
+ // See ClientSocketPool::GetLoadState() for documentation on this function.
LoadState GetLoadState(const std::string& group_name,
const ClientSocketHandle* handle) const;
+ // ConnectJob::Delegate methods:
virtual void OnConnectJobComplete(int result, ConnectJob* job);
// Enables late binding of sockets. In this mode, socket requests are
@@ -182,6 +206,7 @@ class ClientSocketPoolBase
// For testing.
bool may_have_stalled_group() const { return may_have_stalled_group_; }
+
int NumConnectJobsInGroup(const std::string& group_name) const {
return group_map_.find(group_name)->second.jobs.size();
}
@@ -204,8 +229,8 @@ class ClientSocketPoolBase
bool ShouldCleanup(base::TimeTicks now) const;
};
- typedef std::deque<Request> RequestQueue;
- typedef std::map<const ClientSocketHandle*, Request> RequestMap;
+ typedef std::deque<const Request*> RequestQueue;
+ typedef std::map<const ClientSocketHandle*, const Request*> RequestMap;
// A Group is allocated per group_name when there are idle sockets or pending
// requests. Otherwise, the Group object is removed from the map.
@@ -223,7 +248,7 @@ class ClientSocketPoolBase
}
int TopPendingPriority() const {
- return pending_requests.front().priority;
+ return pending_requests.front()->priority();
}
std::deque<IdleSocket> idle_sockets;
@@ -238,7 +263,7 @@ class ClientSocketPoolBase
typedef std::map<const ClientSocketHandle*, ConnectJob*> ConnectJobMap;
typedef std::set<const ConnectJob*> ConnectJobSet;
- static void InsertRequestIntoQueue(const Request& r,
+ static void InsertRequestIntoQueue(const Request* r,
RequestQueue* pending_requests);
// Closes all idle sockets if |force| is true. Else, only closes idle
@@ -267,7 +292,8 @@ class ClientSocketPoolBase
// Removes the ConnectJob corresponding to |handle| from the
// |connect_job_map_| or |connect_job_set_| depending on whether or not late
// binding is enabled. |job| must be non-NULL when late binding is
- // enabled. Also updates |group| if non-NULL.
+ // enabled. Also updates |group| if non-NULL. When late binding is disabled,
+ // this will also delete the Request from |group->connecting_requests|.
void RemoveConnectJob(const ClientSocketHandle* handle,
const ConnectJob* job,
Group* group);
@@ -307,7 +333,7 @@ class ClientSocketPoolBase
// Timer used to periodically prune idle sockets that timed out or can't be
// reused.
- base::RepeatingTimer<ClientSocketPoolBase> timer_;
+ base::RepeatingTimer<ClientSocketPoolBaseHelper> timer_;
// The total number of idle sockets in the system.
int idle_socket_count_;
@@ -345,9 +371,154 @@ class ClientSocketPoolBase
// Controls whether or not we use late binding of sockets.
static bool g_late_binding;
+};
+
+} // namespace internal
+
+template <typename SocketParams>
+class ClientSocketPoolBase {
+ public:
+ class Request : public internal::ClientSocketPoolBaseHelper::Request {
+ public:
+ Request(ClientSocketHandle* handle,
+ CompletionCallback* callback,
+ int priority,
+ const SocketParams& params,
+ LoadLog* load_log)
+ : internal::ClientSocketPoolBaseHelper::Request(
+ handle, callback, priority, load_log),
+ params_(params) {}
+
+ const SocketParams& params() const { return params_; }
+
+ private:
+ SocketParams params_;
+ };
+
+ class ConnectJobFactory {
+ public:
+ ConnectJobFactory() {}
+ virtual ~ConnectJobFactory() {}
+
+ virtual ConnectJob* NewConnectJob(
+ const std::string& group_name,
+ const Request& request,
+ ConnectJob::Delegate* delegate) const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConnectJobFactory);
+ };
+
+ ClientSocketPoolBase(int max_sockets,
+ int max_sockets_per_group,
+ ConnectJobFactory* connect_job_factory)
+ : helper_(new internal::ClientSocketPoolBaseHelper(
+ max_sockets, max_sockets_per_group,
+ new ConnectJobFactoryAdaptor(connect_job_factory))) {}
+
+ ~ClientSocketPoolBase() {}
+
+ // These member functions simply forward to ClientSocketPoolBaseHelper.
+
+ // RequestSocket bundles up the parameters into a Request and then forwards to
+ // ClientSocketPoolBaseHelper::RequestSocket(). Note that the memory
+ // ownership is transferred in the asynchronous (ERR_IO_PENDING) case.
+ int RequestSocket(const std::string& group_name,
+ const SocketParams& params,
+ int priority,
+ ClientSocketHandle* handle,
+ CompletionCallback* callback,
+ LoadLog* load_log) {
+ scoped_ptr<Request> request(
+ new Request(handle, callback, priority, params, load_log));
+ int rv = helper_->RequestSocket(group_name, request.get());
+ if (rv == ERR_IO_PENDING)
+ request.release();
+ return rv;
+ }
+
+ void CancelRequest(const std::string& group_name,
+ const ClientSocketHandle* handle) {
+ return helper_->CancelRequest(group_name, handle);
+ }
+
+ void ReleaseSocket(const std::string& group_name, ClientSocket* socket) {
+ return helper_->ReleaseSocket(group_name, socket);
+ }
+
+ void CloseIdleSockets() { return helper_->CloseIdleSockets(); }
+
+ int idle_socket_count() const { return helper_->idle_socket_count(); }
+
+ int IdleSocketCountInGroup(const std::string& group_name) const {
+ return helper_->IdleSocketCountInGroup(group_name);
+ }
+
+ LoadState GetLoadState(const std::string& group_name,
+ const ClientSocketHandle* handle) const {
+ return helper_->GetLoadState(group_name, handle);
+ }
+
+ virtual void OnConnectJobComplete(int result, ConnectJob* job) {
+ return helper_->OnConnectJobComplete(result, job);
+ }
+
+ // For testing.
+ bool may_have_stalled_group() const {
+ return helper_->may_have_stalled_group();
+ }
+
+ int NumConnectJobsInGroup(const std::string& group_name) const {
+ return helper_->NumConnectJobsInGroup(group_name);
+ }
+
+ private:
+ // This adaptor class exists to bridge the
+ // internal::ClientSocketPoolBaseHelper::ConnectJobFactory and
+ // ClientSocketPoolBase::ConnectJobFactory types, allowing clients to use the
+ // typesafe ClientSocketPoolBase::ConnectJobFactory, rather than having to
+ // static_cast themselves.
+ class ConnectJobFactoryAdaptor
+ : public internal::ClientSocketPoolBaseHelper::ConnectJobFactory {
+ public:
+ typedef typename ClientSocketPoolBase<SocketParams>::ConnectJobFactory
+ ConnectJobFactory;
+
+ explicit ConnectJobFactoryAdaptor(
+ ConnectJobFactory* connect_job_factory)
+ : connect_job_factory_(connect_job_factory) {}
+ virtual ~ConnectJobFactoryAdaptor() {}
+
+ virtual ConnectJob* NewConnectJob(
+ const std::string& group_name,
+ const internal::ClientSocketPoolBaseHelper::Request& request,
+ ConnectJob::Delegate* delegate) const {
+ const Request* casted_request = static_cast<const Request*>(&request);
+ return connect_job_factory_->NewConnectJob(
+ group_name, *casted_request, delegate);
+ }
+
+ const scoped_ptr<ConnectJobFactory> connect_job_factory_;
+ };
+
+ // One might ask why ClientSocketPoolBaseHelper is also refcounted if its
+ // containing ClientSocketPool is already refcounted. The reason is because
+ // DoReleaseSocket() posts a task. If ClientSocketPool gets deleted between
+ // the posting of the task and the execution, then we'll hit the DCHECK that
+ // |ClientSocketPoolBaseHelper::group_map_| is empty.
+ scoped_refptr<internal::ClientSocketPoolBaseHelper> helper_;
+
DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase);
};
+// Enables late binding of sockets. In this mode, socket requests are
+// decoupled from socket connection jobs. A socket request may initiate a
+// socket connection job, but there is no guarantee that that socket
+// connection will service the request (for example, a released socket may
+// service the request sooner, or a higher priority request may come in
+// afterward and receive the socket from the job).
+void EnableLateBindingOfSockets(bool enabled);
+
} // namespace net
#endif // NET_SOCKET_CLIENT_SOCKET_POOL_BASE_H_