Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/socket/websocket_endpoint_lock_manager.h" | 5 #include "net/socket/websocket_endpoint_lock_manager.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "net/base/net_errors.h" | 10 #include "net/base/net_errors.h" |
| 11 #include "net/base/net_log.h" | 11 #include "net/base/net_log.h" |
| 12 | 12 |
| 13 namespace net { | 13 namespace net { |
| 14 | 14 |
| 15 WebSocketEndpointLockManager::Waiter::~Waiter() { | 15 WebSocketEndpointLockManager::Waiter::~Waiter() { |
| 16 if (next()) { | 16 if (next()) { |
| 17 DCHECK(previous()); | 17 DCHECK(previous()); |
| 18 RemoveFromList(); | 18 RemoveFromList(); |
| 19 } | 19 } |
| 20 } | 20 } |
| 21 | 21 |
| 22 WebSocketEndpointLockManager* WebSocketEndpointLockManager::GetInstance() { | 22 WebSocketEndpointLockManager* WebSocketEndpointLockManager::GetInstance() { |
| 23 return Singleton<WebSocketEndpointLockManager>::get(); | 23 return Singleton<WebSocketEndpointLockManager>::get(); |
| 24 } | 24 } |
| 25 | 25 |
| 26 int WebSocketEndpointLockManager::LockEndpoint(const IPEndPoint& endpoint, | 26 int WebSocketEndpointLockManager::LockEndpoint(const IPEndPoint& endpoint, |
| 27 Waiter* waiter) { | 27 Waiter* waiter) { |
| 28 EndPointWaiterMap::value_type insert_value(endpoint, NULL); | 28 LockInfoMap::value_type insert_value(endpoint, LockInfo()); |
| 29 std::pair<EndPointWaiterMap::iterator, bool> rv = | 29 std::pair<LockInfoMap::iterator, bool> rv = |
| 30 endpoint_waiter_map_.insert(insert_value); | 30 lock_info_map_.insert(insert_value); |
| 31 if (rv.second) { | 31 if (rv.second) { |
| 32 DVLOG(3) << "Locking endpoint " << endpoint.ToString(); | 32 DVLOG(3) << "Locking endpoint " << endpoint.ToString(); |
| 33 rv.first->second = new ConnectJobQueue; | 33 rv.first->second.queue.reset(new LockInfo::WaiterQueue); |
| 34 return OK; | 34 return OK; |
| 35 } | 35 } |
| 36 DVLOG(3) << "Waiting for endpoint " << endpoint.ToString(); | 36 DVLOG(3) << "Waiting for endpoint " << endpoint.ToString(); |
| 37 rv.first->second->Append(waiter); | 37 rv.first->second.queue->Append(waiter); |
| 38 return ERR_IO_PENDING; | 38 return ERR_IO_PENDING; |
| 39 } | 39 } |
| 40 | 40 |
| 41 void WebSocketEndpointLockManager::RememberSocket(StreamSocket* socket, | 41 void WebSocketEndpointLockManager::RememberSocket(StreamSocket* socket, |
| 42 const IPEndPoint& endpoint) { | 42 const IPEndPoint& endpoint) { |
| 43 bool inserted = socket_endpoint_map_.insert(SocketEndPointMap::value_type( | 43 LockInfoMap::iterator lock_info_it = lock_info_map_.find(endpoint); |
| 44 socket, endpoint)).second; | 44 CHECK(lock_info_it != lock_info_map_.end()); |
| 45 bool inserted = | |
| 46 socket_lock_info_map_.insert(SocketLockInfoMap::value_type( | |
| 47 socket, lock_info_it)).second; | |
| 45 DCHECK(inserted); | 48 DCHECK(inserted); |
| 46 DCHECK(endpoint_waiter_map_.find(endpoint) != endpoint_waiter_map_.end()); | 49 DCHECK(!lock_info_it->second.socket); |
| 50 lock_info_it->second.socket = socket; | |
| 47 DVLOG(3) << "Remembered (StreamSocket*)" << socket << " for " | 51 DVLOG(3) << "Remembered (StreamSocket*)" << socket << " for " |
| 48 << endpoint.ToString() << " (" << socket_endpoint_map_.size() | 52 << endpoint.ToString() << " (" << socket_lock_info_map_.size() |
| 49 << " sockets remembered)"; | 53 << " socket(s) remembered)"; |
| 50 } | 54 } |
| 51 | 55 |
| 52 void WebSocketEndpointLockManager::UnlockSocket(StreamSocket* socket) { | 56 void WebSocketEndpointLockManager::UnlockSocket(StreamSocket* socket) { |
| 53 SocketEndPointMap::iterator socket_it = socket_endpoint_map_.find(socket); | 57 SocketLockInfoMap::iterator socket_it = socket_lock_info_map_.find(socket); |
| 54 if (socket_it == socket_endpoint_map_.end()) { | 58 if (socket_it == socket_lock_info_map_.end()) |
| 55 DVLOG(3) << "Ignoring request to unlock already-unlocked socket" | |
| 56 "(StreamSocket*)" << socket; | |
| 57 return; | 59 return; |
| 58 } | 60 |
| 59 const IPEndPoint& endpoint = socket_it->second; | 61 LockInfoMap::iterator lock_info_it = socket_it->second; |
| 62 | |
| 60 DVLOG(3) << "Unlocking (StreamSocket*)" << socket << " for " | 63 DVLOG(3) << "Unlocking (StreamSocket*)" << socket << " for " |
| 61 << endpoint.ToString() << " (" << socket_endpoint_map_.size() | 64 << lock_info_it->first.ToString() << " (" |
| 62 << " sockets left)"; | 65 << socket_lock_info_map_.size() << " socket(s) left)"; |
| 63 UnlockEndpoint(endpoint); | 66 socket_lock_info_map_.erase(socket_it); |
| 64 socket_endpoint_map_.erase(socket_it); | 67 DCHECK(socket == lock_info_it->second.socket); |
| 68 lock_info_it->second.socket = NULL; | |
| 69 UnlockEndpointByIterator(lock_info_it); | |
| 65 } | 70 } |
| 66 | 71 |
| 67 void WebSocketEndpointLockManager::UnlockEndpoint(const IPEndPoint& endpoint) { | 72 void WebSocketEndpointLockManager::UnlockEndpoint(const IPEndPoint& endpoint) { |
| 68 EndPointWaiterMap::iterator found_it = endpoint_waiter_map_.find(endpoint); | 73 LockInfoMap::iterator lock_info_it = lock_info_map_.find(endpoint); |
| 69 CHECK(found_it != endpoint_waiter_map_.end()); // Security critical | 74 if (lock_info_it == lock_info_map_.end()) |
| 70 ConnectJobQueue* queue = found_it->second; | 75 return; |
| 71 if (queue->empty()) { | 76 |
| 72 DVLOG(3) << "Unlocking endpoint " << endpoint.ToString(); | 77 UnlockEndpointByIterator(lock_info_it); |
| 73 delete queue; | |
| 74 endpoint_waiter_map_.erase(found_it); | |
| 75 } else { | |
| 76 DVLOG(3) << "Unlocking endpoint " << endpoint.ToString() | |
| 77 << " and activating next waiter"; | |
| 78 Waiter* next_job = queue->head()->value(); | |
| 79 next_job->RemoveFromList(); | |
| 80 next_job->GotEndpointLock(); | |
| 81 } | |
| 82 } | 78 } |
| 83 | 79 |
| 84 bool WebSocketEndpointLockManager::IsEmpty() const { | 80 bool WebSocketEndpointLockManager::IsEmpty() const { |
| 85 return endpoint_waiter_map_.empty() && socket_endpoint_map_.empty(); | 81 return lock_info_map_.empty() && socket_lock_info_map_.empty(); |
| 82 } | |
| 83 | |
| 84 WebSocketEndpointLockManager::LockInfo::LockInfo() : socket(NULL) {} | |
| 85 WebSocketEndpointLockManager::LockInfo::~LockInfo() { | |
| 86 DCHECK(!socket); | |
| 87 } | |
| 88 | |
| 89 WebSocketEndpointLockManager::LockInfo::LockInfo(const LockInfo& rhs) | |
| 90 : socket(rhs.socket) { | |
| 91 DCHECK(!rhs.queue); | |
| 86 } | 92 } |
| 87 | 93 |
| 88 WebSocketEndpointLockManager::WebSocketEndpointLockManager() {} | 94 WebSocketEndpointLockManager::WebSocketEndpointLockManager() {} |
| 89 | 95 |
| 90 WebSocketEndpointLockManager::~WebSocketEndpointLockManager() { | 96 WebSocketEndpointLockManager::~WebSocketEndpointLockManager() { |
| 91 DCHECK(endpoint_waiter_map_.empty()); | 97 DCHECK(lock_info_map_.empty()); |
| 92 DCHECK(socket_endpoint_map_.empty()); | 98 DCHECK(socket_lock_info_map_.empty()); |
| 99 } | |
| 100 | |
| 101 void WebSocketEndpointLockManager::UnlockEndpointByIterator( | |
| 102 LockInfoMap::iterator lock_info_it) { | |
| 103 if (lock_info_it->second.socket) | |
| 104 EraseSocket(lock_info_it); | |
| 105 scoped_ptr<LockInfo::WaiterQueue>& queue = lock_info_it->second.queue; | |
|
tyoshino (SeeGerritForStatus)
2014/08/01 11:31:44
how about just using a pointer?
Adam Rice
2014/08/01 14:09:39
Done.
| |
| 106 if (queue->empty()) { | |
| 107 DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString(); | |
| 108 queue.reset(); | |
|
tyoshino (SeeGerritForStatus)
2014/08/01 11:31:44
then, you need to call it on to lock_info_it->seco
Adam Rice
2014/08/01 14:09:39
I just removed the reset() completely, since the s
| |
| 109 lock_info_map_.erase(lock_info_it); | |
| 110 return; | |
| 111 } | |
| 112 | |
| 113 DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString() | |
| 114 << " and activating next waiter"; | |
| 115 Waiter* next_job = queue->head()->value(); | |
| 116 next_job->RemoveFromList(); | |
| 117 // This must be last to minimise the excitement caused by re-entrancy. | |
| 118 next_job->GotEndpointLock(); | |
| 119 } | |
| 120 | |
| 121 void WebSocketEndpointLockManager::EraseSocket( | |
| 122 LockInfoMap::iterator lock_info_it) { | |
| 123 DVLOG(3) << "Removing (StreamSocket*)" << lock_info_it->second.socket | |
| 124 << " for " << lock_info_it->first.ToString() << " (" | |
| 125 << socket_lock_info_map_.size() << " socket(s) left)"; | |
| 126 size_t erased = socket_lock_info_map_.erase(lock_info_it->second.socket); | |
| 127 DCHECK_EQ(1U, erased); | |
| 128 lock_info_it->second.socket = NULL; | |
| 93 } | 129 } |
| 94 | 130 |
| 95 } // namespace net | 131 } // namespace net |
| OLD | NEW |