| 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/bind.h" |
| 9 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/message_loop/message_loop.h" |
| 10 #include "net/base/net_errors.h" | 12 #include "net/base/net_errors.h" |
| 11 #include "net/base/net_log.h" | 13 #include "net/base/net_log.h" |
| 12 | 14 |
| 13 namespace net { | 15 namespace net { |
| 14 | 16 |
| 17 namespace { |
| 18 |
| 19 // This delay prevents DoS attacks. |
| 20 // TODO(ricea): Replace this with randomised truncated exponential backoff. |
| 21 // See crbug.com/377613. |
| 22 const int kUnlockDelayInMs = 10; |
| 23 |
| 24 } // namespace |
| 25 |
| 15 WebSocketEndpointLockManager::Waiter::~Waiter() { | 26 WebSocketEndpointLockManager::Waiter::~Waiter() { |
| 16 if (next()) { | 27 if (next()) { |
| 17 DCHECK(previous()); | 28 DCHECK(previous()); |
| 18 RemoveFromList(); | 29 RemoveFromList(); |
| 19 } | 30 } |
| 20 } | 31 } |
| 21 | 32 |
| 22 WebSocketEndpointLockManager* WebSocketEndpointLockManager::GetInstance() { | 33 WebSocketEndpointLockManager* WebSocketEndpointLockManager::GetInstance() { |
| 23 return Singleton<WebSocketEndpointLockManager>::get(); | 34 return Singleton<WebSocketEndpointLockManager>::get(); |
| 24 } | 35 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 SocketLockInfoMap::iterator socket_it = socket_lock_info_map_.find(socket); | 69 SocketLockInfoMap::iterator socket_it = socket_lock_info_map_.find(socket); |
| 59 if (socket_it == socket_lock_info_map_.end()) | 70 if (socket_it == socket_lock_info_map_.end()) |
| 60 return; | 71 return; |
| 61 | 72 |
| 62 LockInfoMap::iterator lock_info_it = socket_it->second; | 73 LockInfoMap::iterator lock_info_it = socket_it->second; |
| 63 | 74 |
| 64 DVLOG(3) << "Unlocking (StreamSocket*)" << socket << " for " | 75 DVLOG(3) << "Unlocking (StreamSocket*)" << socket << " for " |
| 65 << lock_info_it->first.ToString() << " (" | 76 << lock_info_it->first.ToString() << " (" |
| 66 << socket_lock_info_map_.size() << " socket(s) left)"; | 77 << socket_lock_info_map_.size() << " socket(s) left)"; |
| 67 socket_lock_info_map_.erase(socket_it); | 78 socket_lock_info_map_.erase(socket_it); |
| 68 DCHECK(socket == lock_info_it->second.socket); | 79 DCHECK_EQ(socket, lock_info_it->second.socket); |
| 69 lock_info_it->second.socket = NULL; | 80 lock_info_it->second.socket = NULL; |
| 70 UnlockEndpointByIterator(lock_info_it); | 81 UnlockEndpointAfterDelay(lock_info_it->first); |
| 71 } | 82 } |
| 72 | 83 |
| 73 void WebSocketEndpointLockManager::UnlockEndpoint(const IPEndPoint& endpoint) { | 84 void WebSocketEndpointLockManager::UnlockEndpoint(const IPEndPoint& endpoint) { |
| 74 LockInfoMap::iterator lock_info_it = lock_info_map_.find(endpoint); | 85 LockInfoMap::iterator lock_info_it = lock_info_map_.find(endpoint); |
| 75 if (lock_info_it == lock_info_map_.end()) | 86 if (lock_info_it == lock_info_map_.end()) |
| 76 return; | 87 return; |
| 77 | 88 if (lock_info_it->second.socket) |
| 78 UnlockEndpointByIterator(lock_info_it); | 89 EraseSocket(lock_info_it); |
| 90 UnlockEndpointAfterDelay(endpoint); |
| 79 } | 91 } |
| 80 | 92 |
| 81 bool WebSocketEndpointLockManager::IsEmpty() const { | 93 bool WebSocketEndpointLockManager::IsEmpty() const { |
| 82 return lock_info_map_.empty() && socket_lock_info_map_.empty(); | 94 return lock_info_map_.empty() && socket_lock_info_map_.empty(); |
| 83 } | 95 } |
| 84 | 96 |
| 97 base::TimeDelta WebSocketEndpointLockManager::SetUnlockDelayForTesting( |
| 98 base::TimeDelta new_delay) { |
| 99 base::TimeDelta old_delay = unlock_delay_; |
| 100 unlock_delay_ = new_delay; |
| 101 return old_delay; |
| 102 } |
| 103 |
| 85 WebSocketEndpointLockManager::LockInfo::LockInfo() : socket(NULL) {} | 104 WebSocketEndpointLockManager::LockInfo::LockInfo() : socket(NULL) {} |
| 86 WebSocketEndpointLockManager::LockInfo::~LockInfo() { | 105 WebSocketEndpointLockManager::LockInfo::~LockInfo() { |
| 87 DCHECK(!socket); | 106 DCHECK(!socket); |
| 88 } | 107 } |
| 89 | 108 |
| 90 WebSocketEndpointLockManager::LockInfo::LockInfo(const LockInfo& rhs) | 109 WebSocketEndpointLockManager::LockInfo::LockInfo(const LockInfo& rhs) |
| 91 : socket(rhs.socket) { | 110 : socket(rhs.socket) { |
| 92 DCHECK(!rhs.queue); | 111 DCHECK(!rhs.queue); |
| 93 } | 112 } |
| 94 | 113 |
| 95 WebSocketEndpointLockManager::WebSocketEndpointLockManager() {} | 114 WebSocketEndpointLockManager::WebSocketEndpointLockManager() |
| 115 : unlock_delay_(base::TimeDelta::FromMilliseconds(kUnlockDelayInMs)), |
| 116 pending_unlock_count_(0), |
| 117 weak_factory_(this) { |
| 118 } |
| 96 | 119 |
| 97 WebSocketEndpointLockManager::~WebSocketEndpointLockManager() { | 120 WebSocketEndpointLockManager::~WebSocketEndpointLockManager() { |
| 98 DCHECK(lock_info_map_.empty()); | 121 DCHECK_EQ(lock_info_map_.size(), pending_unlock_count_); |
| 99 DCHECK(socket_lock_info_map_.empty()); | 122 DCHECK(socket_lock_info_map_.empty()); |
| 100 } | 123 } |
| 101 | 124 |
| 102 void WebSocketEndpointLockManager::UnlockEndpointByIterator( | 125 void WebSocketEndpointLockManager::UnlockEndpointAfterDelay( |
| 103 LockInfoMap::iterator lock_info_it) { | 126 const IPEndPoint& endpoint) { |
| 104 if (lock_info_it->second.socket) | 127 DVLOG(3) << "Delaying " << unlock_delay_.InMilliseconds() |
| 105 EraseSocket(lock_info_it); | 128 << "ms before unlocking endpoint " << endpoint.ToString(); |
| 129 ++pending_unlock_count_; |
| 130 base::MessageLoop::current()->PostDelayedTask( |
| 131 FROM_HERE, |
| 132 base::Bind(&WebSocketEndpointLockManager::DelayedUnlockEndpoint, |
| 133 weak_factory_.GetWeakPtr(), endpoint), |
| 134 unlock_delay_); |
| 135 } |
| 136 |
| 137 void WebSocketEndpointLockManager::DelayedUnlockEndpoint( |
| 138 const IPEndPoint& endpoint) { |
| 139 LockInfoMap::iterator lock_info_it = lock_info_map_.find(endpoint); |
| 140 DCHECK_GT(pending_unlock_count_, 0U); |
| 141 --pending_unlock_count_; |
| 142 if (lock_info_it == lock_info_map_.end()) |
| 143 return; |
| 144 DCHECK(!lock_info_it->second.socket); |
| 106 LockInfo::WaiterQueue* queue = lock_info_it->second.queue.get(); | 145 LockInfo::WaiterQueue* queue = lock_info_it->second.queue.get(); |
| 107 DCHECK(queue); | 146 DCHECK(queue); |
| 108 if (queue->empty()) { | 147 if (queue->empty()) { |
| 109 DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString(); | 148 DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString(); |
| 110 lock_info_map_.erase(lock_info_it); | 149 lock_info_map_.erase(lock_info_it); |
| 111 return; | 150 return; |
| 112 } | 151 } |
| 113 | 152 |
| 114 DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString() | 153 DVLOG(3) << "Unlocking endpoint " << lock_info_it->first.ToString() |
| 115 << " and activating next waiter"; | 154 << " and activating next waiter"; |
| 116 Waiter* next_job = queue->head()->value(); | 155 Waiter* next_job = queue->head()->value(); |
| 117 next_job->RemoveFromList(); | 156 next_job->RemoveFromList(); |
| 118 // This must be last to minimise the excitement caused by re-entrancy. | |
| 119 next_job->GotEndpointLock(); | 157 next_job->GotEndpointLock(); |
| 120 } | 158 } |
| 121 | 159 |
| 122 void WebSocketEndpointLockManager::EraseSocket( | 160 void WebSocketEndpointLockManager::EraseSocket( |
| 123 LockInfoMap::iterator lock_info_it) { | 161 LockInfoMap::iterator lock_info_it) { |
| 124 DVLOG(3) << "Removing (StreamSocket*)" << lock_info_it->second.socket | 162 DVLOG(3) << "Removing (StreamSocket*)" << lock_info_it->second.socket |
| 125 << " for " << lock_info_it->first.ToString() << " (" | 163 << " for " << lock_info_it->first.ToString() << " (" |
| 126 << socket_lock_info_map_.size() << " socket(s) left)"; | 164 << socket_lock_info_map_.size() << " socket(s) left)"; |
| 127 size_t erased = socket_lock_info_map_.erase(lock_info_it->second.socket); | 165 size_t erased = socket_lock_info_map_.erase(lock_info_it->second.socket); |
| 128 DCHECK_EQ(1U, erased); | 166 DCHECK_EQ(1U, erased); |
| 129 lock_info_it->second.socket = NULL; | 167 lock_info_it->second.socket = NULL; |
| 130 } | 168 } |
| 131 | 169 |
| 132 } // namespace net | 170 } // namespace net |
| OLD | NEW |