1 // Copyright 2014 The Chromium Authors 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/memory/raw_ptr.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 54 LockReleaser(const LockReleaser&) = delete; 55 LockReleaser& operator=(const LockReleaser&) = delete; 56 57 ~LockReleaser(); 58 59 private: 60 friend class WebSocketEndpointLockManager; 61 62 // This is null if UnlockEndpoint() has been called before this object was 63 // destroyed. 64 raw_ptr<WebSocketEndpointLockManager> websocket_endpoint_lock_manager_; 65 const IPEndPoint endpoint_; 66 }; 67 68 WebSocketEndpointLockManager(); 69 70 WebSocketEndpointLockManager(const WebSocketEndpointLockManager&) = delete; 71 WebSocketEndpointLockManager& operator=(const WebSocketEndpointLockManager&) = 72 delete; 73 74 ~WebSocketEndpointLockManager(); 75 76 // Returns OK if lock was acquired immediately, ERR_IO_PENDING if not. If the 77 // lock was not acquired, then |waiter->GotEndpointLock()| will be called when 78 // it is. A Waiter automatically removes itself from the list of waiters when 79 // its destructor is called. 80 int LockEndpoint(const IPEndPoint& endpoint, Waiter* waiter); 81 82 // Asynchronously releases the lock on |endpoint| after a delay. Does nothing 83 // if |endpoint| is not locked. If a LockReleaser object has been created for 84 // this endpoint, it will be unregistered. 85 void UnlockEndpoint(const IPEndPoint& endpoint); 86 87 // Checks that |lock_info_map_| is empty. For tests. 88 bool IsEmpty() const; 89 90 // Changes the value of the unlock delay. Returns the previous value of the 91 // delay. 92 base::TimeDelta SetUnlockDelayForTesting(base::TimeDelta new_delay); 93 94 private: 95 struct LockInfo { 96 typedef base::LinkedList<Waiter> WaiterQueue; 97 98 LockInfo(); 99 ~LockInfo(); 100 101 // This object must be copyable to be placed in the map, but it cannot be 102 // copied after |queue| has been assigned to. 103 LockInfo(const LockInfo& rhs); 104 105 // Not used. 106 LockInfo& operator=(const LockInfo& rhs); 107 108 // Must be NULL to copy this object into the map. Must be set to non-NULL 109 // after the object is inserted into the map then point to the same list 110 // until this object is deleted. 111 std::unique_ptr<WaiterQueue> queue; 112 113 // This pointer is non-NULL if a LockReleaser object has been constructed 114 // since the last call to UnlockEndpoint(). 115 raw_ptr<LockReleaser> lock_releaser; 116 }; 117 118 // SocketLockInfoMap requires std::map iterator semantics for LockInfoMap 119 // (ie. that the iterator will remain valid as long as the entry is not 120 // deleted). 121 typedef std::map<IPEndPoint, LockInfo> LockInfoMap; 122 123 // Records the association of a LockReleaser with a particular endpoint. 124 void RegisterLockReleaser(LockReleaser* lock_releaser, IPEndPoint endpoint); 125 void UnlockEndpointAfterDelay(const IPEndPoint& endpoint); 126 void DelayedUnlockEndpoint(const IPEndPoint& endpoint); 127 128 // If an entry is present in the map for a particular endpoint, then that 129 // endpoint is locked. If LockInfo.queue is non-empty, then one or more 130 // Waiters are waiting for the lock. 131 LockInfoMap lock_info_map_; 132 133 // Time to wait between a call to Unlock* and actually unlocking the socket. 134 base::TimeDelta unlock_delay_; 135 136 // Number of sockets currently pending unlock. 137 size_t pending_unlock_count_ = 0; 138 139 base::WeakPtrFactory<WebSocketEndpointLockManager> weak_factory_{this}; 140 }; 141 142 } // namespace net 143 144 #endif // NET_SOCKET_WEBSOCKET_ENDPOINT_LOCK_MANAGER_H_ 145