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 <stddef.h> 9 10 #include <map> 11 #include <memory> 12 13 #include "base/containers/linked_list.h" 14 #include "base/macros.h" 15 #include "base/time/time.h" 16 #include "net/base/ip_endpoint.h" 17 #include "net/base/net_export.h" 18 #include "net/socket/websocket_transport_client_socket_pool.h" 19 20 namespace net { 21 22 // Keep track of ongoing WebSocket connections in order to satisfy the WebSocket 23 // connection throttling requirements described in RFC6455 4.1.2: 24 // 25 // 2. If the client already has a WebSocket connection to the remote 26 // host (IP address) identified by /host/ and port /port/ pair, even 27 // if the remote host is known by another name, the client MUST wait 28 // until that connection has been established or for that connection 29 // to have failed. There MUST be no more than one connection in a 30 // CONNECTING state. If multiple connections to the same IP address 31 // are attempted simultaneously, the client MUST serialize them so 32 // that there is no more than one connection at a time running 33 // through the following steps. 34 // 35 class NET_EXPORT_PRIVATE WebSocketEndpointLockManager { 36 public: 37 // Implement this interface to wait for an endpoint to be available. 38 class NET_EXPORT_PRIVATE Waiter : public base::LinkNode<Waiter> { 39 public: 40 // If the node is in a list, removes it. 41 virtual ~Waiter(); 42 43 virtual void GotEndpointLock() = 0; 44 }; 45 46 // LockReleaser calls UnlockEndpoint() when it is destroyed, but only if it 47 // has not already been called. Only one LockReleaser object may exist for 48 // each endpoint at a time. 49 class NET_EXPORT_PRIVATE LockReleaser final { 50 public: 51 LockReleaser(WebSocketEndpointLockManager* websocket_endpoint_lock_manager, 52 IPEndPoint endpoint); 53 ~LockReleaser(); 54 55 private: 56 friend class WebSocketEndpointLockManager; 57 58 // This is null if UnlockEndpoint() has been called before this object was 59 // destroyed. 60 WebSocketEndpointLockManager* websocket_endpoint_lock_manager_; 61 const IPEndPoint endpoint_; 62 63 DISALLOW_COPY_AND_ASSIGN(LockReleaser); 64 }; 65 66 WebSocketEndpointLockManager(); 67 ~WebSocketEndpointLockManager(); 68 69 // Returns OK if lock was acquired immediately, ERR_IO_PENDING if not. If the 70 // lock was not acquired, then |waiter->GotEndpointLock()| will be called when 71 // it is. A Waiter automatically removes itself from the list of waiters when 72 // its destructor is called. 73 int LockEndpoint(const IPEndPoint& endpoint, Waiter* waiter); 74 75 // Asynchronously releases the lock on |endpoint| after a delay. Does nothing 76 // if |endpoint| is not locked. If a LockReleaser object has been created for 77 // this endpoint, it will be unregistered. 78 void UnlockEndpoint(const IPEndPoint& endpoint); 79 80 // Checks that |lock_info_map_| is empty. For tests. 81 bool IsEmpty() const; 82 83 // Changes the value of the unlock delay. Returns the previous value of the 84 // delay. 85 base::TimeDelta SetUnlockDelayForTesting(base::TimeDelta new_delay); 86 87 private: 88 struct LockInfo { 89 typedef base::LinkedList<Waiter> WaiterQueue; 90 91 LockInfo(); 92 ~LockInfo(); 93 94 // This object must be copyable to be placed in the map, but it cannot be 95 // copied after |queue| has been assigned to. 96 LockInfo(const LockInfo& rhs); 97 98 // Not used. 99 LockInfo& operator=(const LockInfo& rhs); 100 101 // Must be NULL to copy this object into the map. Must be set to non-NULL 102 // after the object is inserted into the map then point to the same list 103 // until this object is deleted. 104 std::unique_ptr<WaiterQueue> queue; 105 106 // This pointer is non-NULL if a LockReleaser object has been constructed 107 // since the last call to UnlockEndpoint(). 108 LockReleaser* lock_releaser; 109 }; 110 111 // SocketLockInfoMap requires std::map iterator semantics for LockInfoMap 112 // (ie. that the iterator will remain valid as long as the entry is not 113 // deleted). 114 typedef std::map<IPEndPoint, LockInfo> LockInfoMap; 115 116 // Records the association of a LockReleaser with a particular endpoint. 117 void RegisterLockReleaser(LockReleaser* lock_releaser, IPEndPoint endpoint); 118 void UnlockEndpointAfterDelay(const IPEndPoint& endpoint); 119 void DelayedUnlockEndpoint(const IPEndPoint& endpoint); 120 121 // If an entry is present in the map for a particular endpoint, then that 122 // endpoint is locked. If LockInfo.queue is non-empty, then one or more 123 // Waiters are waiting for the lock. 124 LockInfoMap lock_info_map_; 125 126 // Time to wait between a call to Unlock* and actually unlocking the socket. 127 base::TimeDelta unlock_delay_; 128 129 // Number of sockets currently pending unlock. 130 size_t pending_unlock_count_; 131 132 base::WeakPtrFactory<WebSocketEndpointLockManager> weak_factory_{this}; 133 134 DISALLOW_COPY_AND_ASSIGN(WebSocketEndpointLockManager); 135 }; 136 137 } // namespace net 138 139 #endif // NET_SOCKET_WEBSOCKET_ENDPOINT_LOCK_MANAGER_H_ 140