// Copyright 2014 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_WEBSOCKET_ENDPOINT_LOCK_MANAGER_H_ #define NET_SOCKET_WEBSOCKET_ENDPOINT_LOCK_MANAGER_H_ #include #include "base/containers/linked_list.h" #include "base/logging.h" #include "base/macros.h" #include "base/memory/singleton.h" #include "net/base/ip_endpoint.h" #include "net/base/net_export.h" #include "net/socket/websocket_transport_client_socket_pool.h" namespace net { class StreamSocket; class NET_EXPORT_PRIVATE WebSocketEndpointLockManager { public: class NET_EXPORT_PRIVATE Waiter : public base::LinkNode { public: // If the node is in a list, removes it. virtual ~Waiter(); virtual void GotEndpointLock() = 0; }; static WebSocketEndpointLockManager* GetInstance(); // Returns OK if lock was acquired immediately, ERR_IO_PENDING if not. If the // lock was not acquired, then |waiter->GotEndpointLock()| will be called when // it is. A Waiter automatically removes itself from the list of waiters when // its destructor is called. int LockEndpoint(const IPEndPoint& endpoint, Waiter* waiter); // Records the IPEndPoint associated with a particular socket. This is // necessary because TCPClientSocket refuses to return the PeerAddress after // the connection is disconnected. The association will be forgotten when // UnlockSocket() is called. The |socket| pointer must not be deleted between // the call to RememberSocket() and the call to UnlockSocket(). void RememberSocket(StreamSocket* socket, const IPEndPoint& endpoint); // Releases the lock on an endpoint, and, if appropriate, triggers the next // socket connection. For a successful WebSocket connection, this method will // be called once when the handshake completes, and again when the connection // is closed. Calls after the first are safely ignored. void UnlockSocket(StreamSocket* socket); // Releases the lock on |endpoint|. If RememberSocket() has been called for // this endpoint, then UnlockSocket() must be used instead of this method. void UnlockEndpoint(const IPEndPoint& endpoint); // Checks that |endpoint_waiter_map_| and |socket_endpoint_map_| are // empty. For tests. bool IsEmpty() const; private: typedef base::LinkedList ConnectJobQueue; typedef std::map EndPointWaiterMap; typedef std::map SocketEndPointMap; WebSocketEndpointLockManager(); ~WebSocketEndpointLockManager(); // If an entry is present in the map for a particular endpoint, then that // endpoint is locked. If the list is non-empty, then one or more Waiters are // waiting for the lock. EndPointWaiterMap endpoint_waiter_map_; // Store sockets remembered by RememberSocket() and not yet unlocked by // UnlockSocket(). SocketEndPointMap socket_endpoint_map_; friend struct DefaultSingletonTraits; DISALLOW_COPY_AND_ASSIGN(WebSocketEndpointLockManager); }; } // namespace net #endif // NET_SOCKET_WEBSOCKET_ENDPOINT_LOCK_MANAGER_H_