Index: content/browser/renderer_host/websocket_dispatcher_host.cc |
diff --git a/content/browser/renderer_host/websocket_dispatcher_host.cc b/content/browser/renderer_host/websocket_dispatcher_host.cc |
index d49199a7cb8f44e08ea03435a58905f63b618fc5..fc9aef4477e4a18d6f5e5ed7b3aec4486fda4839 100644 |
--- a/content/browser/renderer_host/websocket_dispatcher_host.cc |
+++ b/content/browser/renderer_host/websocket_dispatcher_host.cc |
@@ -9,6 +9,7 @@ |
#include "base/callback.h" |
#include "base/logging.h" |
+#include "base/rand_util.h" |
#include "base/stl_util.h" |
#include "content/browser/child_process_security_policy_impl.h" |
#include "content/browser/renderer_host/websocket_host.h" |
@@ -33,7 +34,12 @@ WebSocketDispatcherHost::WebSocketDispatcherHost( |
get_context_callback_(get_context_callback), |
websocket_host_factory_( |
base::Bind(&WebSocketDispatcherHost::CreateWebSocketHost, |
- base::Unretained(this))) {} |
+ base::Unretained(this))), |
+ num_pending_connections_(0), |
+ num_current_succeeded_connections_(0), |
+ num_previous_succeeded_connections_(0), |
+ num_current_failed_connections_(0), |
+ num_previous_failed_connections_(0) {} |
WebSocketDispatcherHost::WebSocketDispatcherHost( |
int process_id, |
@@ -44,8 +50,10 @@ WebSocketDispatcherHost::WebSocketDispatcherHost( |
get_context_callback_(get_context_callback), |
websocket_host_factory_(websocket_host_factory) {} |
-WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id) { |
- return new WebSocketHost(routing_id, this, get_context_callback_.Run()); |
+WebSocketHost* WebSocketDispatcherHost::CreateWebSocketHost(int routing_id, |
+ int delay_in_ms) { |
+ return new WebSocketHost(routing_id, this, get_context_callback_.Run(), |
+ delay_in_ms); |
} |
bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) { |
@@ -73,8 +81,23 @@ bool WebSocketDispatcherHost::OnMessageReceived(const IPC::Message& message) { |
// little extreme. So for now just ignore the bogus request. |
return true; // We handled the message (by ignoring it). |
} |
- host = websocket_host_factory_.Run(routing_id); |
+ if (num_pending_connections_ > 255) { // FIXME: 255 |
Adam Rice
2015/03/03 15:10:02
Nitpick: use "TODO(hiroshige)" rather than "FIXME"
hiroshige
2015/03/04 06:02:37
Done.
|
+ if(!Send(new WebSocketMsg_NotifyFailure(routing_id, |
+ "Error in connection establishment: net::ERR_INSUFFICIENT_RESOURCES" |
+ ))) { |
+ DVLOG(1) << "Sending of message type " |
+ << "WebSocketMsg_NotifyFailure failed."; |
+ } |
+ return true; |
+ } |
+ host = websocket_host_factory_.Run(routing_id, CalculateDelayInMs()); |
hosts_.insert(WebSocketHostTable::value_type(routing_id, host)); |
+ ++num_pending_connections_; |
+ if (!timer_.IsRunning()) |
+ timer_.Start(FROM_HERE, |
+ base::TimeDelta::FromMinutes(2), |
+ this, |
+ &WebSocketDispatcherHost::FinishThrottlingPeriod); |
} |
if (!host) { |
DVLOG(1) << "Received invalid routing ID " << routing_id |
@@ -121,6 +144,15 @@ WebSocketHostState WebSocketDispatcherHost::SendAddChannelResponse( |
DeleteWebSocketHost(routing_id); |
return WEBSOCKET_HOST_DELETED; |
} |
+ |
+ // Update throttling counters (success). |
+ WebSocketHost* host = GetHost(routing_id); |
+ DCHECK(host); |
+ host->OnHandshakeSucceeded(); |
+ --num_pending_connections_; |
+ DCHECK(num_pending_connections_ >= 0); |
Adam Rice
2015/03/03 15:10:02
Nitpick: Use DCHECK_GE().
hiroshige
2015/03/04 06:02:37
Done.
|
+ ++num_current_succeeded_connections_; |
Adam Rice
2015/03/03 15:10:02
Are we sure that num_current_succeeded_connections
hiroshige
2015/03/04 06:02:37
About >9M successful (or failed) handshakes per se
Adam Rice
2015/03/04 08:20:49
9M successes per second would never be possible wi
Adam Rice
2015/03/04 08:35:10
Another approach would be to stop incrementing num
|
+ |
return WEBSOCKET_HOST_ALIVE; |
} |
@@ -200,8 +232,42 @@ WebSocketDispatcherHost::~WebSocketDispatcherHost() { |
void WebSocketDispatcherHost::DeleteWebSocketHost(int routing_id) { |
WebSocketHostTable::iterator it = hosts_.find(routing_id); |
DCHECK(it != hosts_.end()); |
+ |
+ if (!it->second->handshakeSucceeded()) { |
+ // Update throttling counters (failure). |
+ --num_pending_connections_; |
+ DCHECK(num_pending_connections_ >= 0); |
+ ++num_current_failed_connections_; |
+ } |
+ |
delete it->second; |
hosts_.erase(it); |
+ |
+ DCHECK(static_cast<size_t>(num_pending_connections_) <= hosts_.size()); |
+} |
+ |
+int64 WebSocketDispatcherHost::CalculateDelayInMs() const { |
Adam Rice
2015/03/03 15:10:02
This would be a good place to have a link to the d
hiroshige
2015/03/04 06:02:37
Done.
|
+ int f = num_previous_failed_connections_ + |
+ num_current_failed_connections_; |
+ int s = num_previous_succeeded_connections_ + |
+ num_current_succeeded_connections_; |
+ int p = num_pending_connections_; |
+ return base::RandInt(1000, 5000) * |
+ (1 << std::min(p + f / (s + 1), 16)) / 65536; |
+} |
+ |
+void WebSocketDispatcherHost::FinishThrottlingPeriod() { |
+ num_previous_failed_connections_ = num_current_failed_connections_; |
+ num_current_failed_connections_ = 0; |
+ |
+ num_previous_succeeded_connections_ = num_current_succeeded_connections_; |
+ num_current_succeeded_connections_ = 0; |
+ |
+ if (num_pending_connections_ == 0 && |
+ num_previous_failed_connections_ == 0 && |
+ num_previous_succeeded_connections_ == 0) { |
+ timer_.Stop(); |
+ } |
} |
} // namespace content |