summaryrefslogtreecommitdiffstats
path: root/net/socket/tcp_client_socket_pool.h
diff options
context:
space:
mode:
authorwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-22 23:26:44 +0000
committerwillchan@chromium.org <willchan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-06-22 23:26:44 +0000
commitf7984fc67f3c88b6ff1c738700a8229f387d732d (patch)
tree094f6be7633d60b0413370462bf6bd04b906ac00 /net/socket/tcp_client_socket_pool.h
parent8c1be4e0311d52f07fe16fc091862957757dc002 (diff)
downloadchromium_src-f7984fc67f3c88b6ff1c738700a8229f387d732d.zip
chromium_src-f7984fc67f3c88b6ff1c738700a8229f387d732d.tar.gz
chromium_src-f7984fc67f3c88b6ff1c738700a8229f387d732d.tar.bz2
Move socket related files from net/base to net/socket.
Review URL: http://codereview.chromium.org/144009 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18985 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/socket/tcp_client_socket_pool.h')
-rw-r--r--net/socket/tcp_client_socket_pool.h340
1 files changed, 340 insertions, 0 deletions
diff --git a/net/socket/tcp_client_socket_pool.h b/net/socket/tcp_client_socket_pool.h
new file mode 100644
index 0000000..e237be5
--- /dev/null
+++ b/net/socket/tcp_client_socket_pool.h
@@ -0,0 +1,340 @@
+// 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.
+
+#ifndef NET_SOCKET_TCP_CLIENT_SOCKET_POOL_H_
+#define NET_SOCKET_TCP_CLIENT_SOCKET_POOL_H_
+
+#include <deque>
+#include <map>
+#include <string>
+
+#include "base/scoped_ptr.h"
+#include "base/timer.h"
+#include "net/base/address_list.h"
+#include "net/base/host_resolver.h"
+#include "net/socket/client_socket_pool.h"
+
+namespace net {
+
+class ClientSocketFactory;
+class ClientSocketPoolBase;
+
+// ConnectingSocket provides an abstract interface for "connecting" a socket.
+// The connection may involve host resolution, tcp connection, ssl connection,
+// etc.
+class ConnectingSocket {
+ public:
+ ConnectingSocket() {}
+ virtual ~ConnectingSocket() {}
+
+ // Begins connecting the socket. Returns OK on success, ERR_IO_PENDING if it
+ // cannot complete synchronously without blocking, or another net error code
+ // on error.
+ virtual int Connect() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConnectingSocket);
+};
+
+// TCPConnectingSocket handles the host resolution necessary for socket creation
+// and the tcp connect.
+class TCPConnectingSocket : public ConnectingSocket {
+ public:
+ TCPConnectingSocket(const std::string& group_name,
+ const HostResolver::RequestInfo& resolve_info,
+ const ClientSocketHandle* handle,
+ ClientSocketFactory* client_socket_factory,
+ ClientSocketPoolBase* pool);
+ ~TCPConnectingSocket();
+
+ // ConnectingSocket methods.
+
+ // Begins the host resolution and the TCP connect. Returns OK on success
+ // and ERR_IO_PENDING if it cannot immediately service the request.
+ // Otherwise, it returns a net error code.
+ virtual int Connect();
+
+ private:
+ // Handles asynchronous completion of IO. |result| represents the result of
+ // the IO operation.
+ void OnIOComplete(int result);
+
+ // Handles both asynchronous and synchronous completion of IO. |result|
+ // represents the result of the IO operation. |synchronous| indicates
+ // whether or not the previous IO operation completed synchronously or
+ // asynchronously. OnIOCompleteInternal returns the result of the next IO
+ // operation that executes, or just the value of |result|.
+ int OnIOCompleteInternal(int result, bool synchronous);
+
+ const std::string group_name_;
+ const HostResolver::RequestInfo resolve_info_;
+ const ClientSocketHandle* const handle_;
+ ClientSocketFactory* const client_socket_factory_;
+ CompletionCallbackImpl<TCPConnectingSocket> callback_;
+ scoped_ptr<ClientSocket> socket_;
+ ClientSocketPoolBase* const pool_;
+ SingleRequestHostResolver resolver_;
+ AddressList addresses_;
+
+ // The time the Connect() method was called (if it got called).
+ base::TimeTicks connect_start_time_;
+
+ DISALLOW_COPY_AND_ASSIGN(TCPConnectingSocket);
+};
+
+// 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> {
+ 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() : resolve_info(std::string(), 0) {}
+
+ Request(ClientSocketHandle* handle,
+ CompletionCallback* callback,
+ int priority,
+ const HostResolver::RequestInfo& resolve_info,
+ LoadState load_state)
+ : handle(handle), callback(callback), priority(priority),
+ resolve_info(resolve_info), load_state(load_state) {
+ }
+
+ ClientSocketHandle* handle;
+ CompletionCallback* callback;
+ int priority;
+ HostResolver::RequestInfo resolve_info;
+ LoadState load_state;
+ };
+
+ class ConnectingSocketFactory {
+ public:
+ ConnectingSocketFactory() {}
+ virtual ~ConnectingSocketFactory() {}
+
+ virtual ConnectingSocket* NewConnectingSocket(
+ const std::string& group_name,
+ const Request& request,
+ ClientSocketPoolBase* pool) const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ConnectingSocketFactory);
+ };
+
+ ClientSocketPoolBase(int max_sockets_per_group,
+ HostResolver* host_resolver,
+ ConnectingSocketFactory* connecting_socket_factory);
+
+ ~ClientSocketPoolBase();
+
+ int RequestSocket(const std::string& group_name,
+ const HostResolver::RequestInfo& resolve_info,
+ int priority,
+ ClientSocketHandle* handle,
+ CompletionCallback* callback);
+
+ void CancelRequest(const std::string& group_name,
+ const ClientSocketHandle* handle);
+
+ void ReleaseSocket(const std::string& group_name,
+ ClientSocket* socket);
+
+ void CloseIdleSockets();
+
+ HostResolver* GetHostResolver() const {
+ return host_resolver_;
+ }
+
+ int idle_socket_count() const {
+ return idle_socket_count_;
+ }
+
+ int IdleSocketCountInGroup(const std::string& group_name) const;
+
+ LoadState GetLoadState(const std::string& group_name,
+ const ClientSocketHandle* handle) const;
+
+ // Used by ConnectingSocket until we remove the coupling between a specific
+ // ConnectingSocket and a ClientSocketHandle:
+
+ // Returns NULL if not found. Otherwise it returns the Request*
+ // corresponding to the ConnectingSocket (keyed by |group_name| and |handle|.
+ // Note that this pointer may be invalidated after any call that might mutate
+ // the RequestMap or GroupMap, so the user should not hold onto the pointer
+ // for long.
+ Request* GetConnectingRequest(const std::string& group_name,
+ const ClientSocketHandle* handle);
+
+ // Handles the completed Request corresponding to the ConnectingSocket (keyed
+ // by |group_name| and |handle|. |deactivate| indicates whether or not to
+ // deactivate the socket, making the socket slot available for a new socket
+ // connection. If |deactivate| is false, then set |socket| into |handle|.
+ // Returns the callback to run.
+ CompletionCallback* OnConnectingRequestComplete(
+ const std::string& group_name,
+ const ClientSocketHandle* handle,
+ bool deactivate,
+ ClientSocket* socket);
+
+ private:
+ // Entry for a persistent socket which became idle at time |start_time|.
+ struct IdleSocket {
+ ClientSocket* socket;
+ base::TimeTicks start_time;
+
+ // An idle socket should be removed if it can't be reused, or has been idle
+ // for too long. |now| is the current time value (TimeTicks::Now()).
+ //
+ // An idle socket can't be reused if it is disconnected or has received
+ // data unexpectedly (hence no longer idle). The unread data would be
+ // mistaken for the beginning of the next response if we were to reuse the
+ // socket for a new request.
+ bool ShouldCleanup(base::TimeTicks now) const;
+ };
+
+ typedef std::deque<Request> RequestQueue;
+ typedef std::map<const ClientSocketHandle*, 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.
+ struct Group {
+ Group() : active_socket_count(0), sockets_handed_out_count(0) {}
+ std::deque<IdleSocket> idle_sockets;
+ RequestQueue pending_requests;
+ RequestMap connecting_requests;
+ int active_socket_count; // number of active sockets
+ int sockets_handed_out_count; // number of sockets given to clients
+ };
+
+ typedef std::map<std::string, Group> GroupMap;
+
+ typedef std::map<const ClientSocketHandle*, ConnectingSocket*>
+ ConnectingSocketMap;
+
+ static void InsertRequestIntoQueue(const Request& r,
+ RequestQueue* pending_requests);
+
+ // Closes all idle sockets if |force| is true. Else, only closes idle
+ // sockets that timed out or can't be reused.
+ void CleanupIdleSockets(bool force);
+
+ // Called when the number of idle sockets changes.
+ void IncrementIdleCount();
+ void DecrementIdleCount();
+
+ // Called via PostTask by ReleaseSocket.
+ void DoReleaseSocket(const std::string& group_name, ClientSocket* socket);
+
+ // Called when timer_ fires. This method scans the idle sockets removing
+ // sockets that timed out or can't be reused.
+ void OnCleanupTimerFired() {
+ CleanupIdleSockets(false);
+ }
+
+ // Removes the ConnectingSocket corresponding to |handle| from the
+ // |connecting_socket_map_|.
+ void RemoveConnectingSocket(const ClientSocketHandle* handle);
+
+ static void CheckSocketCounts(const Group& group);
+
+ // Process a request from a group's pending_requests queue.
+ void ProcessPendingRequest(const std::string& group_name, Group* group);
+
+ GroupMap group_map_;
+
+ ConnectingSocketMap connecting_socket_map_;
+
+ // Timer used to periodically prune idle sockets that timed out or can't be
+ // reused.
+ base::RepeatingTimer<ClientSocketPoolBase> timer_;
+
+ // The total number of idle sockets in the system.
+ int idle_socket_count_;
+
+ // The maximum number of sockets kept per group.
+ const int max_sockets_per_group_;
+
+ // The host resolver that will be used to do DNS lookups for connecting
+ // sockets.
+ HostResolver* const host_resolver_;
+
+ scoped_ptr<ConnectingSocketFactory> connecting_socket_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClientSocketPoolBase);
+};
+
+class TCPClientSocketPool : public ClientSocketPool {
+ public:
+ TCPClientSocketPool(int max_sockets_per_group,
+ HostResolver* host_resolver,
+ ClientSocketFactory* client_socket_factory);
+
+ // ClientSocketPool methods:
+
+ virtual int RequestSocket(const std::string& group_name,
+ const HostResolver::RequestInfo& resolve_info,
+ int priority,
+ ClientSocketHandle* handle,
+ CompletionCallback* callback);
+
+ virtual void CancelRequest(const std::string& group_name,
+ const ClientSocketHandle* handle);
+
+ virtual void ReleaseSocket(const std::string& group_name,
+ ClientSocket* socket);
+
+ virtual void CloseIdleSockets();
+
+ virtual HostResolver* GetHostResolver() const {
+ return base_->GetHostResolver();
+ }
+
+ virtual int IdleSocketCount() const {
+ return base_->idle_socket_count();
+ }
+
+ virtual int IdleSocketCountInGroup(const std::string& group_name) const;
+
+ virtual LoadState GetLoadState(const std::string& group_name,
+ const ClientSocketHandle* handle) const;
+
+ private:
+ virtual ~TCPClientSocketPool();
+
+ class TCPConnectingSocketFactory
+ : public ClientSocketPoolBase::ConnectingSocketFactory {
+ public:
+ TCPConnectingSocketFactory(ClientSocketFactory* client_socket_factory)
+ : client_socket_factory_(client_socket_factory) {}
+
+ virtual ~TCPConnectingSocketFactory() {}
+
+ // ClientSocketPoolBase::ConnectingSocketFactory methods.
+
+ virtual ConnectingSocket* NewConnectingSocket(
+ const std::string& group_name,
+ const ClientSocketPoolBase::Request& request,
+ ClientSocketPoolBase* pool) const;
+
+ private:
+ ClientSocketFactory* const client_socket_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TCPConnectingSocketFactory);
+ };
+
+ // One might ask why ClientSocketPoolBase 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
+ // |ClientSocketPoolBase::group_map_| is empty.
+ scoped_refptr<ClientSocketPoolBase> base_;
+
+ DISALLOW_COPY_AND_ASSIGN(TCPClientSocketPool);
+};
+
+} // namespace net
+
+#endif // NET_SOCKET_TCP_CLIENT_SOCKET_POOL_H_