Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: net/socket/websocket_endpoint_lock_manager.cc

Issue 835623003: Add a delay when unlocking WebSocket endpoints. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Document WebSocketEndpointLockManager Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
OLDNEW
« no previous file with comments | « net/socket/websocket_endpoint_lock_manager.h ('k') | net/socket/websocket_endpoint_lock_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698