summaryrefslogtreecommitdiffstats
path: root/net/base/client_socket_pool.h
blob: 99e49362203c63396d426b01cc2c86205fd9c0ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// 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_BASE_CLIENT_SOCKET_POOL_H_
#define NET_BASE_CLIENT_SOCKET_POOL_H_

#include <deque>
#include <map>
#include <string>

#include "base/ref_counted.h"
#include "base/timer.h"
#include "net/base/completion_callback.h"

namespace net {

class ClientSocket;
class ClientSocketHandle;

// A ClientSocketPool is used to restrict the number of sockets open at a time.
// It also maintains a list of idle persistent sockets.
//
// The ClientSocketPool allocates scoped_ptr<ClientSocket> objects, but it is
// not responsible for allocating the associated ClientSocket objects.  The
// consumer must do so if it gets a scoped_ptr<ClientSocket> with a null value.
//
class ClientSocketPool : public base::RefCounted<ClientSocketPool>,
                         public Task {
 public:
  explicit ClientSocketPool(int max_sockets_per_group);

  // Called to request a socket for the given handle.  There are three possible
  // results: 1) the handle will be initialized with a socket to reuse, 2) the
  // handle will be initialized without a socket such that the consumer needs
  // to supply a socket, or 3) the handle will be added to a wait list until a
  // socket is available to reuse or the opportunity to create a new socket
  // arises.  The completion callback is notified in the 3rd case.
  //
  // If this function returns OK, then |handle| is initialized upon return.
  // The |handle|'s is_initialized method will return true in this case.  If a
  // ClientSocket was reused, then |handle|'s socket member will be non-NULL.
  // Otherwise, the consumer will need to supply |handle| with a socket by
  // allocating a new ClientSocket object and calling the |handle|'s set_socket
  // method.
  //
  // If ERR_IO_PENDING is returned, then the completion callback will be called
  // when |handle| has been initialized.
  //
  int RequestSocket(ClientSocketHandle* handle, CompletionCallback* callback);

  // Called to cancel a RequestSocket call that returned ERR_IO_PENDING.  The
  // same handle parameter must be passed to this method as was passed to the
  // RequestSocket call being cancelled.  The associated CompletionCallback is
  // not run.
  void CancelRequest(ClientSocketHandle* handle);

  // Called to release the socket member of an initialized ClientSocketHandle
  // once the socket is no longer needed.  If the socket member is non-null and
  // still has an established connection, then it will be added to the idle set
  // of sockets to be used to satisfy future RequestSocket calls.  Otherwise,
  // the ClientSocket is destroyed.
  void ReleaseSocket(ClientSocketHandle* handle);

  // Called to close any idle connections held by the connection manager.
  void CloseIdleSockets();

 private:
  friend class base::RefCounted<ClientSocketPool>;

  typedef scoped_ptr<ClientSocket> ClientSocketPtr;

  ~ClientSocketPool();

  // Closes all idle sockets if |only_if_disconnected| is false.  Else, only
  // idle sockets that are disconnected get closed.  "Maybe" refers to the
  // fact that it doesn't close all idle sockets if |only_if_disconnected| is
  // true.
  void MaybeCloseIdleSockets(bool only_if_disconnected);

  // Called when the number of idle sockets changes.
  void IncrementIdleCount();
  void DecrementIdleCount();

  // Called via PostTask by ReleaseSocket.
  void DoReleaseSocket(const std::string& group_name, ClientSocketPtr* ptr);

  // Task implementation.  This method scans the idle sockets checking to see
  // if any have been disconnected.
  virtual void Run();

  // A Request is allocated per call to RequestSocket that results in
  // ERR_IO_PENDING.
  struct Request {
    ClientSocketHandle* handle;
    CompletionCallback* callback;
  };

  // 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) {}
    std::deque<ClientSocketPtr*> idle_sockets;
    std::deque<Request> pending_requests;
    int active_socket_count;
  };

  typedef std::map<std::string, Group> GroupMap;
  GroupMap group_map_;

  // Timer used to periodically prune sockets that have been disconnected.
  RepeatingTimer timer_;

  // The total number of idle sockets in the system.
  int idle_socket_count_;

  // The maximum number of sockets kept per group.
  int max_sockets_per_group_;
};

}  // namespace net

#endif  // NET_BASE_CLIENT_SOCKET_POOL_H_