GUAC-1512: Add absolute connection limit properties for MySQL/PostgreSQL.
Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/commit/0a95e161 Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/0a95e161 Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/0a95e161 Branch: refs/heads/master Commit: 0a95e16151e953f7b9bf9abb25c07e89a5b43b5e Parents: b0d890d Author: Michael Jumper <[email protected]> Authored: Thu Mar 17 00:51:29 2016 -0700 Committer: Michael Jumper <[email protected]> Committed: Thu Mar 17 00:56:43 2016 -0700 ---------------------------------------------------------------------- .../guacamole/auth/jdbc/JDBCEnvironment.java | 14 +++++ .../RestrictedGuacamoleTunnelService.java | 63 ++++++++++++++++++++ .../net/auth/mysql/MySQLEnvironment.java | 13 ++++ .../auth/mysql/MySQLGuacamoleProperties.java | 13 ++++ .../auth/postgresql/PostgreSQLEnvironment.java | 13 ++++ .../PostgreSQLGuacamoleProperties.java | 13 ++++ 6 files changed, 129 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/0a95e161/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCEnvironment.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCEnvironment.java index f7a3a6f..fe944f9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCEnvironment.java @@ -45,6 +45,20 @@ public abstract class JDBCEnvironment extends LocalEnvironment { } /** + * Returns the maximum number of concurrent connections to allow overall. + * As this limit applies globally (independent of which connection is in + * use or which user is using it), this setting cannot be overridden at the + * connection level. Zero denotes unlimited. + * + * @return + * The maximum allowable number of concurrent connections. + * + * @throws GuacamoleException + * If an error occurs while retrieving the property. + */ + public abstract int getAbsoluteMaxConnections() throws GuacamoleException; + + /** * Returns the default maximum number of concurrent connections to allow to * any one connection, unless specified differently on an individual * connection. Zero denotes unlimited. http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/0a95e161/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/RestrictedGuacamoleTunnelService.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/RestrictedGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/RestrictedGuacamoleTunnelService.java index 7f5f283..b57649e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/RestrictedGuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/RestrictedGuacamoleTunnelService.java @@ -23,15 +23,18 @@ package org.glyptodon.guacamole.auth.jdbc.tunnel; import com.google.common.collect.ConcurrentHashMultiset; +import com.google.inject.Inject; import com.google.inject.Singleton; import java.util.Arrays; import java.util.Comparator; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import org.glyptodon.guacamole.GuacamoleClientTooManyException; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleResourceConflictException; +import org.glyptodon.guacamole.auth.jdbc.JDBCEnvironment; import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; @@ -48,6 +51,12 @@ public class RestrictedGuacamoleTunnelService extends AbstractGuacamoleTunnelService { /** + * The environment of the Guacamole server. + */ + @Inject + private JDBCEnvironment environment; + + /** * Set of all currently-active user/connection pairs (seats). */ private final ConcurrentHashMultiset<Seat> activeSeats = ConcurrentHashMultiset.<Seat>create(); @@ -68,6 +77,12 @@ public class RestrictedGuacamoleTunnelService private final ConcurrentHashMultiset<String> activeGroups = ConcurrentHashMultiset.<String>create(); /** + * The total number of active connections within this instance of + * Guacamole. + */ + private final AtomicInteger totalActiveConnections = new AtomicInteger(0); + + /** * Attempts to add a single instance of the given value to the given * multiset without exceeding the specified maximum number of values. If * the value cannot be added without exceeding the maximum, false is @@ -113,10 +128,54 @@ public class RestrictedGuacamoleTunnelService } + /** + * Attempts to increment the given AtomicInteger without exceeding the + * specified maximum value. If the AtomicInteger cannot be incremented + * without exceeding the maximum, false is returned. + * + * @param counter + * The AtomicInteger to attempt increment. + * + * @param max + * The maximum value that the given AtomicInteger should contain, or + * zero if no limit applies. + * + * @return + * true if the AtomicInteger was successfully incremented without + * exceeding the specified maximum, false if the AtomicInteger could + * not be incremented. + */ + private boolean tryIncrement(AtomicInteger counter, int max) { + + // Repeatedly attempt to increment the given AtomicInteger until we + // explicitly succeed or explicitly fail + while (true) { + + // Get current value + int count = counter.get(); + + // Bail out if the maximum has already been reached + if (count >= max && max != 0) + return false; + + // Attempt to increment + if (counter.compareAndSet(count, count+1)) + return true; + + // Try again if unsuccessful + + } + + } + @Override protected ModeledConnection acquire(AuthenticatedUser user, List<ModeledConnection> connections) throws GuacamoleException { + // Do not acquire connection unless within overall limits + if (!tryIncrement(totalActiveConnections, environment.getAbsoluteMaxConnections())) + throw new GuacamoleResourceConflictException("Cannot connect. Overall maximum connections reached."); + // Get username String username = user.getUser().getIdentifier(); @@ -160,6 +219,9 @@ public class RestrictedGuacamoleTunnelService } + // Acquire failed + totalActiveConnections.decrementAndGet(); + // Too many connections by this user if (userSpecificFailure) throw new GuacamoleClientTooManyException("Cannot connect. Connection already in use by this user."); @@ -174,6 +236,7 @@ public class RestrictedGuacamoleTunnelService protected void release(AuthenticatedUser user, ModeledConnection connection) { activeSeats.remove(new Seat(user.getUser().getIdentifier(), connection.getIdentifier())); activeConnections.remove(connection.getIdentifier()); + totalActiveConnections.decrementAndGet(); } @Override http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/0a95e161/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java index 90a42af..4cf474b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLEnvironment.java @@ -52,6 +52,12 @@ public class MySQLEnvironment extends JDBCEnvironment { private static final int DEFAULT_PORT = 3306; /** + * The default value for the maximum number of connections to be + * allowed to the Guacamole server overall. + */ + private final int ABSOLUTE_MAX_CONNECTIONS = 0; + + /** * The default value for the default maximum number of connections to be * allowed per user to any one connection. Note that, as long as the * legacy "disallow duplicate" and "disallow simultaneous" properties are @@ -165,6 +171,13 @@ public class MySQLEnvironment extends JDBCEnvironment { } @Override + public int getAbsoluteMaxConnections() throws GuacamoleException { + return getProperty(MySQLGuacamoleProperties.MYSQL_ABSOLUTE_MAX_CONNECTIONS, + ABSOLUTE_MAX_CONNECTIONS + ); + } + + @Override public int getDefaultMaxConnections() throws GuacamoleException { return getProperty( MySQLGuacamoleProperties.MYSQL_DEFAULT_MAX_CONNECTIONS, http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/0a95e161/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java index cb0c35b..7a81daf 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLGuacamoleProperties.java @@ -116,6 +116,19 @@ public class MySQLGuacamoleProperties { }; /** + * The maximum number of concurrent connections to allow overall. Zero + * denotes unlimited. + */ + public static final IntegerGuacamoleProperty + MYSQL_ABSOLUTE_MAX_CONNECTIONS = + new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "mysql-absolute-max-connections"; } + + }; + + /** * The maximum number of concurrent connections to allow to any one * connection. Zero denotes unlimited. */ http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/0a95e161/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLEnvironment.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLEnvironment.java index 83c139e..a87ffec 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLEnvironment.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLEnvironment.java @@ -51,6 +51,12 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { private static final int DEFAULT_PORT = 5432; /** + * The default value for the maximum number of connections to be + * allowed to the Guacamole server overall. + */ + private final int ABSOLUTE_MAX_CONNECTIONS = 0; + + /** * The default value for the default maximum number of connections to be * allowed per user to any one connection. Note that, as long as the * legacy "disallow duplicate" and "disallow simultaneous" properties are @@ -164,6 +170,13 @@ public class PostgreSQLEnvironment extends JDBCEnvironment { } @Override + public int getAbsoluteMaxConnections() throws GuacamoleException { + return getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_ABSOLUTE_MAX_CONNECTIONS, + ABSOLUTE_MAX_CONNECTIONS + ); + } + + @Override public int getDefaultMaxConnections() throws GuacamoleException { return getProperty( PostgreSQLGuacamoleProperties.POSTGRESQL_DEFAULT_MAX_CONNECTIONS, http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/0a95e161/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLGuacamoleProperties.java ---------------------------------------------------------------------- diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLGuacamoleProperties.java index cf41038..8b87ce0 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLGuacamoleProperties.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLGuacamoleProperties.java @@ -125,6 +125,19 @@ public class PostgreSQLGuacamoleProperties { }; /** + * The maximum number of concurrent connections to allow overall. Zero + * denotes unlimited. + */ + public static final IntegerGuacamoleProperty + POSTGRESQL_ABSOLUTE_MAX_CONNECTIONS = + new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-absolute-max-connections"; } + + }; + + /** * The maximum number of concurrent connections to allow to any one * connection. Zero denotes unlimited. */
