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_ENDPOINT_LOCK_MANAGER_H_
6#define NET_SOCKET_WEBSOCKET_ENDPOINT_LOCK_MANAGER_H_
7
8#include <map>
9
10#include "base/containers/linked_list.h"
11#include "base/logging.h"
12#include "base/macros.h"
13#include "base/memory/singleton.h"
14#include "net/base/ip_endpoint.h"
15#include "net/base/net_export.h"
16#include "net/socket/websocket_transport_client_socket_pool.h"
17
18namespace net {
19
20class StreamSocket;
21
22class NET_EXPORT_PRIVATE WebSocketEndpointLockManager {
23 public:
24  class NET_EXPORT_PRIVATE Waiter : public base::LinkNode<Waiter> {
25   public:
26    // If the node is in a list, removes it.
27    virtual ~Waiter();
28
29    virtual void GotEndpointLock() = 0;
30  };
31
32  static WebSocketEndpointLockManager* GetInstance();
33
34  // Returns OK if lock was acquired immediately, ERR_IO_PENDING if not. If the
35  // lock was not acquired, then |waiter->GotEndpointLock()| will be called when
36  // it is. A Waiter automatically removes itself from the list of waiters when
37  // its destructor is called.
38  int LockEndpoint(const IPEndPoint& endpoint, Waiter* waiter);
39
40  // Records the IPEndPoint associated with a particular socket. This is
41  // necessary because TCPClientSocket refuses to return the PeerAddress after
42  // the connection is disconnected. The association will be forgotten when
43  // UnlockSocket() or UnlockEndpoint() is called. The |socket| pointer must not
44  // be deleted between the call to RememberSocket() and the call to
45  // UnlockSocket().
46  void RememberSocket(StreamSocket* socket, const IPEndPoint& endpoint);
47
48  // Releases the lock on the endpoint that was associated with |socket| by
49  // RememberSocket(). If appropriate, triggers the next socket connection.
50  // Should be called exactly once for each |socket| that was passed to
51  // RememberSocket(). Does nothing if UnlockEndpoint() has been called since
52  // the call to RememberSocket().
53  void UnlockSocket(StreamSocket* socket);
54
55  // Releases the lock on |endpoint|. Does nothing if |endpoint| is not locked.
56  // Removes any socket association that was recorded with RememberSocket(). If
57  // appropriate, calls |waiter->GotEndpointLock()|.
58  void UnlockEndpoint(const IPEndPoint& endpoint);
59
60  // Checks that |lock_info_map_| and |socket_lock_info_map_| are empty. For
61  // tests.
62  bool IsEmpty() const;
63
64 private:
65  struct LockInfo {
66    typedef base::LinkedList<Waiter> WaiterQueue;
67
68    LockInfo();
69    ~LockInfo();
70
71    // This object must be copyable to be placed in the map, but it cannot be
72    // copied after |queue| has been assigned to.
73    LockInfo(const LockInfo& rhs);
74
75    // Not used.
76    LockInfo& operator=(const LockInfo& rhs);
77
78    // Must be NULL to copy this object into the map. Must be set to non-NULL
79    // after the object is inserted into the map then point to the same list
80    // until this object is deleted.
81    scoped_ptr<WaiterQueue> queue;
82
83    // This pointer is only used to identify the last instance of StreamSocket
84    // that was passed to RememberSocket() for this endpoint. It should only be
85    // compared with other pointers. It is never dereferenced and not owned. It
86    // is non-NULL if RememberSocket() has been called for this endpoint since
87    // the last call to UnlockSocket() or UnlockEndpoint().
88    StreamSocket* socket;
89  };
90
91  // SocketLockInfoMap requires std::map iterator semantics for LockInfoMap
92  // (ie. that the iterator will remain valid as long as the entry is not
93  // deleted).
94  typedef std::map<IPEndPoint, LockInfo> LockInfoMap;
95  typedef std::map<StreamSocket*, LockInfoMap::iterator> SocketLockInfoMap;
96
97  WebSocketEndpointLockManager();
98  ~WebSocketEndpointLockManager();
99
100  void UnlockEndpointByIterator(LockInfoMap::iterator lock_info_it);
101  void EraseSocket(LockInfoMap::iterator lock_info_it);
102
103  // If an entry is present in the map for a particular endpoint, then that
104  // endpoint is locked. If LockInfo.queue is non-empty, then one or more
105  // Waiters are waiting for the lock.
106  LockInfoMap lock_info_map_;
107
108  // Store sockets remembered by RememberSocket() and not yet unlocked by
109  // UnlockSocket() or UnlockEndpoint(). Every entry in this map always
110  // references a live entry in lock_info_map_, and the LockInfo::socket member
111  // is non-NULL if and only if there is an entry in this map for the socket.
112  SocketLockInfoMap socket_lock_info_map_;
113
114  friend struct DefaultSingletonTraits<WebSocketEndpointLockManager>;
115
116  DISALLOW_COPY_AND_ASSIGN(WebSocketEndpointLockManager);
117};
118
119}  // namespace net
120
121#endif  // NET_SOCKET_WEBSOCKET_ENDPOINT_LOCK_MANAGER_H_
122