* VRFS-2045 - guard against too many concurrent connections

This commit is contained in:
Seth Call 2014-08-14 11:35:17 -05:00
parent 90ec0b3f1a
commit 776704fdf5
8 changed files with 30 additions and 3 deletions

View File

@ -235,6 +235,10 @@
context.JK.JamServer.registerOnSocketClosed(socketClosed);
}
function registerServerRejection() {
logger.debug("register for server rejection");
context.JK.JamServer.registerMessageCallback(context.JK.MessageType.SERVER_REJECTION_ERROR, serverRejection);
}
/**
* Called whenever the websocket closes; this gives us a chance to cleanup things that should be stopped/cleared
@ -247,6 +251,14 @@
}
function serverRejection(header, payload) {
logger.warn("server rejected our websocket connection. reason=" + payload.error_msg)
if(payload.error_msg == 'max_user_connections') {
context.JK.Banner.showAlert("Too Many Connections", "You have too many connections to the server. If you believe this is in error, please contact support.")
}
}
///////////////////
/// RECONNECT /////
///////////////////
@ -672,6 +684,7 @@
registerLoginAck();
registerHeartbeatAck();
registerServerRejection();
registerSocketClosed();
$inSituBanner = $('.server-connection');

View File

@ -115,6 +115,7 @@ if defined?(Bundler)
# Runs the websocket gateway within the web app
config.websocket_gateway_uri = "ws://localhost:#{config.websocket_gateway_port}/websocket"
config.websocket_gateway_trusted_uri = "ws://localhost:#{config.websocket_gateway_port + 1}/websocket"
config.websocket_gateway_max_connections_per_user = 10
config.external_hostname = ENV['EXTERNAL_HOSTNAME'] || 'localhost'
config.external_port = ENV['EXTERNAL_PORT'] || 3000

View File

@ -13,6 +13,7 @@ unless $rails_rake_task
:connect_time_expire_client => APP_CONFIG.websocket_gateway_connect_time_expire_client,
:connect_time_stale_browser => APP_CONFIG.websocket_gateway_connect_time_stale_browser,
:connect_time_expire_browser=> APP_CONFIG.websocket_gateway_connect_time_expire_browser,
:max_connections_per_user => APP_CONFIG.websocket_gateway_max_connections_per_user,
:rabbitmq_host => APP_CONFIG.rabbitmq_host,
:rabbitmq_port => APP_CONFIG.rabbitmq_port,
:calling_thread => current,

View File

@ -51,6 +51,7 @@ Server.new.run(:port => config["port"],
:connect_time_expire_client => config["connect_time_expire_client"],
:connect_time_stale_browser => config["connect_time_stale_browser"],
:connect_time_expire_browser => config["connect_time_expire_browser"],
:max_connections_per_user => config["max_connections_per_user"],
:rabbitmq_host => config['rabbitmq_host'],
:rabbitmq_port => config['rabbitmq_port'],
:cidr => config['cidr'])

View File

@ -4,6 +4,7 @@ Defaults: &defaults
connect_time_stale_browser: 40
connect_time_expire_browser: 60
cidr: [0.0.0.0/0]
max_connections_per_user: 20
development:
port: 6767

View File

@ -26,7 +26,8 @@ module JamWebsockets
:connect_time_stale_client,
:heartbeat_interval_browser,
:connect_time_expire_browser,
:connect_time_stale_browser
:connect_time_stale_browser,
:max_connections_per_user
def initialize()
@log = Logging.logger[self]
@ -49,7 +50,7 @@ module JamWebsockets
@ar_base_logger = ::Logging::Repository.instance[ActiveRecord::Base]
end
def start(connect_time_stale_client, connect_time_expire_client, connect_time_stale_browser, connect_time_expire_browser, options={:host => "localhost", :port => 5672}, &block)
def start(connect_time_stale_client, connect_time_expire_client, connect_time_stale_browser, connect_time_expire_browser, options={:host => "localhost", :port => 5672, :max_connections_per_user => 10}, &block)
@log.info "startup"
@ -59,6 +60,7 @@ module JamWebsockets
@heartbeat_interval_browser = connect_time_stale_browser / 2
@connect_time_stale_browser = connect_time_stale_browser
@connect_time_expire_browser = connect_time_expire_browser
@max_connections_per_user = options[:max_connections_per_user]
begin
@amqp_connection_manager = AmqpConnectionManager.new(true, 4, :host => options[:host], :port => options[:port])
@ -566,6 +568,12 @@ module JamWebsockets
user = valid_login(username, password, token, client_id)
# protect against this user swamping the server
@log.error "CONNENCTION COUNT #{Connection.where(user_id: user.id).count} MAX CONNECTIONS #{@max_connections_per_user}"
if Connection.where(user_id: user.id).count >= @max_connections_per_user
raise SessionError, 'max_user_connections'
end
# XXX This logic needs to instead be handled by a broadcast out to all websockets indicating dup
# kill any websocket connections that have this same client_id, which can happen in race conditions
# this code must happen here, before we go any further, so that there is only one websocket connection per client_id

View File

@ -20,6 +20,7 @@ module JamWebsockets
connect_time_expire_client = options[:connect_time_expire_client].to_i
connect_time_stale_browser = options[:connect_time_stale_browser].to_i
connect_time_expire_browser = options[:connect_time_expire_browser].to_i
max_connections_per_user = options[:max_connections_per_user].to_i
rabbitmq_host = options[:rabbitmq_host]
rabbitmq_port = options[:rabbitmq_port].to_i
calling_thread = options[:calling_thread]
@ -33,7 +34,7 @@ module JamWebsockets
}
EventMachine.run do
@router.start(connect_time_stale_client, connect_time_expire_client, connect_time_stale_browser, connect_time_expire_browser, host: rabbitmq_host, port: rabbitmq_port) do
@router.start(connect_time_stale_client, connect_time_expire_client, connect_time_stale_browser, connect_time_expire_browser, host: rabbitmq_host, port: rabbitmq_port, max_connections_per_user: max_connections_per_user) do
start_connection_expiration
start_connection_flagger
start_websocket_listener(host, port, trust_port, trust_check, options[:emwebsocket_debug])

View File

@ -111,6 +111,7 @@ describe Router do
@router.heartbeat_interval_client = @router.connect_time_stale_client / 2
@router.connect_time_expire_browser = 60
@router.connect_time_stale_browser = 40
@router.max_connections_per_user = 10
@router.heartbeat_interval_browser = @router.connect_time_stale_browser / 2
@router.amqp_connection_manager = AmqpConnectionManager.new(true, 4, host: 'localhost', port: 5672)
end