Index: net/socket/websocket_endpoint_lock_manager.cc |
diff --git a/net/socket/websocket_endpoint_lock_manager.cc b/net/socket/websocket_endpoint_lock_manager.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..c8d9a3b0a4602ab2cf93c249df3f2be34c7e5229 |
--- /dev/null |
+++ b/net/socket/websocket_endpoint_lock_manager.cc |
@@ -0,0 +1,95 @@ |
+// 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. |
+ |
+#include "net/socket/websocket_endpoint_lock_manager.h" |
+ |
+#include <utility> |
+ |
+#include "base/logging.h" |
+#include "net/base/net_errors.h" |
+#include "net/base/net_log.h" |
+ |
+namespace net { |
+ |
+WebSocketEndpointLockManager::Waiter::~Waiter() { |
+ if (next()) { |
+ DCHECK(previous()); |
+ RemoveFromList(); |
+ } |
+} |
+ |
+WebSocketEndpointLockManager* WebSocketEndpointLockManager::GetInstance() { |
+ return Singleton<WebSocketEndpointLockManager>::get(); |
+} |
+ |
+int WebSocketEndpointLockManager::LockEndpoint(const IPEndPoint& endpoint, |
+ Waiter* waiter) { |
+ EndPointWaiterMap::value_type insert_value(endpoint, NULL); |
+ std::pair<EndPointWaiterMap::iterator, bool> rv = |
+ endpoint_waiter_map_.insert(insert_value); |
+ if (rv.second) { |
+ DVLOG(3) << "Locking endpoint " << endpoint.ToString(); |
+ rv.first->second = new ConnectJobQueue; |
+ return OK; |
+ } |
+ DVLOG(3) << "Waiting for endpoint " << endpoint.ToString(); |
+ rv.first->second->Append(waiter); |
+ return ERR_IO_PENDING; |
+} |
+ |
+void WebSocketEndpointLockManager::RememberSocket(StreamSocket* socket, |
+ const IPEndPoint& endpoint) { |
+ bool inserted = socket_endpoint_map_.insert(SocketEndPointMap::value_type( |
+ socket, endpoint)).second; |
+ DCHECK(inserted); |
+ DCHECK(endpoint_waiter_map_.find(endpoint) != endpoint_waiter_map_.end()); |
+ DVLOG(3) << "Remembered (StreamSocket*)" << socket << " for " |
+ << endpoint.ToString() << " (" << socket_endpoint_map_.size() |
+ << " sockets remembered)"; |
+} |
+ |
+void WebSocketEndpointLockManager::UnlockSocket(StreamSocket* socket) { |
+ SocketEndPointMap::iterator socket_it = socket_endpoint_map_.find(socket); |
+ if (socket_it == socket_endpoint_map_.end()) { |
+ DVLOG(3) << "Ignoring request to unlock already-unlocked socket" |
+ "(StreamSocket*)" << socket; |
+ return; |
+ } |
+ const IPEndPoint& endpoint = socket_it->second; |
+ DVLOG(3) << "Unlocking (StreamSocket*)" << socket << " for " |
+ << endpoint.ToString() << " (" << socket_endpoint_map_.size() |
+ << " sockets left)"; |
+ UnlockEndpoint(endpoint); |
+ socket_endpoint_map_.erase(socket_it); |
+} |
+ |
+void WebSocketEndpointLockManager::UnlockEndpoint(const IPEndPoint& endpoint) { |
+ EndPointWaiterMap::iterator found_it = endpoint_waiter_map_.find(endpoint); |
+ CHECK(found_it != endpoint_waiter_map_.end()); // Security critical |
+ ConnectJobQueue* queue = found_it->second; |
+ if (queue->empty()) { |
+ DVLOG(3) << "Unlocking endpoint " << endpoint.ToString(); |
+ delete queue; |
+ endpoint_waiter_map_.erase(found_it); |
+ } else { |
+ DVLOG(3) << "Unlocking endpoint " << endpoint.ToString() |
+ << " and activating next waiter"; |
+ Waiter* next_job = queue->head()->value(); |
+ next_job->RemoveFromList(); |
+ next_job->GotEndpointLock(); |
+ } |
+} |
+ |
+bool WebSocketEndpointLockManager::IsEmpty() const { |
+ return endpoint_waiter_map_.empty() && socket_endpoint_map_.empty(); |
+} |
+ |
+WebSocketEndpointLockManager::WebSocketEndpointLockManager() {} |
+ |
+WebSocketEndpointLockManager::~WebSocketEndpointLockManager() { |
+ DCHECK(endpoint_waiter_map_.empty()); |
+ DCHECK(socket_endpoint_map_.empty()); |
+} |
+ |
+} // namespace net |