mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 00:53:21 +00:00 
			
		
		
		
	GUAC-574: Synchronize across ActiveConnectionMap to prevent connection usage race conditions. Need to revisit architecture of connection management within MySQL.
This commit is contained in:
		| @@ -39,7 +39,7 @@ public class MySQLGuacamoleSocket implements GuacamoleSocket { | ||||
|      * Injected ActiveConnectionMap which will contain all active connections. | ||||
|      */ | ||||
|     @Inject | ||||
|     private ActiveConnectionMap activeConnectionSet; | ||||
|     private ActiveConnectionMap activeConnectionMap; | ||||
|  | ||||
|     /** | ||||
|      * The wrapped socket. | ||||
| @@ -67,7 +67,7 @@ public class MySQLGuacamoleSocket implements GuacamoleSocket { | ||||
|      * @param connectionGroupID The ID of the balancing connection group that is | ||||
|      *                          being connected to; null if not used. | ||||
|      */ | ||||
|     public void init(GuacamoleSocket socket, int connectionID, int userID,  | ||||
|     public void init(GuacamoleSocket socket, | ||||
|             int historyID, Integer connectionGroupID) { | ||||
|         this.socket = socket; | ||||
|         this.historyID = historyID; | ||||
| @@ -91,7 +91,10 @@ public class MySQLGuacamoleSocket implements GuacamoleSocket { | ||||
|         socket.close(); | ||||
|  | ||||
|         // Mark this connection as inactive | ||||
|         activeConnectionSet.closeConnection(historyID, connectionGroupID); | ||||
|         synchronized (activeConnectionMap) { | ||||
|             activeConnectionMap.closeConnection(historyID, connectionGroupID); | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|   | ||||
| @@ -176,7 +176,7 @@ public class ConnectionGroupService { | ||||
|      * Connect to the connection within the given group with the lowest number | ||||
|      * of currently active users. | ||||
|      * | ||||
|      * @param connection The group to load balance across. | ||||
|      * @param group The group to load balance across. | ||||
|      * @param info The information to use when performing the connection | ||||
|      *             handshake. | ||||
|      * @param userID The ID of the user who is connecting to the socket. | ||||
| @@ -186,36 +186,41 @@ public class ConnectionGroupService { | ||||
|      */ | ||||
|     public GuacamoleSocket connect(MySQLConnectionGroup group,  | ||||
|             GuacamoleClientInformation info, int userID) throws GuacamoleException { | ||||
|          | ||||
|         | ||||
|         // Get all connections in the group. | ||||
|         List<Integer> connectionIDs = connectionService.getAllConnectionIDs | ||||
|                 (group.getConnectionGroupID()); | ||||
|          | ||||
|         // Get the least used connection. | ||||
|         Integer leastUsedConnectionID =  | ||||
|                 activeConnectionMap.getLeastUsedConnection(connectionIDs); | ||||
|          | ||||
|         if(leastUsedConnectionID == null) | ||||
|             throw new GuacamoleResourceNotFoundException("No connections found in group."); | ||||
|          | ||||
|         if(GuacamoleProperties.getProperty( | ||||
|                 MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false) | ||||
|                 && activeConnectionMap.isActive(leastUsedConnectionID)) | ||||
|             throw new GuacamoleServerBusyException | ||||
|                     ("Cannot connect. All connections are in use."); | ||||
|          | ||||
|         if(GuacamoleProperties.getProperty( | ||||
|                 MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS, true) | ||||
|                 && activeConnectionMap.isConnectionGroupUserActive(group.getConnectionGroupID(), userID)) | ||||
|             throw new GuacamoleClientTooManyException | ||||
|                     ("Cannot connect. Connection group already in use by this user."); | ||||
|          | ||||
|         // Get the connection  | ||||
|         MySQLConnection connection = connectionService | ||||
|                 .retrieveConnection(leastUsedConnectionID, userID); | ||||
|          | ||||
|         // Connect to the connection | ||||
|         return connectionService.connect(connection, info, userID, group.getConnectionGroupID()); | ||||
|         synchronized (activeConnectionMap) { | ||||
|  | ||||
|             // Get the least used connection. | ||||
|             Integer leastUsedConnectionID =  | ||||
|                     activeConnectionMap.getLeastUsedConnection(connectionIDs); | ||||
|              | ||||
|             if(leastUsedConnectionID == null) | ||||
|                 throw new GuacamoleResourceNotFoundException("No connections found in group."); | ||||
|              | ||||
|             if(GuacamoleProperties.getProperty( | ||||
|                     MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false) | ||||
|                     && activeConnectionMap.isActive(leastUsedConnectionID)) | ||||
|                 throw new GuacamoleServerBusyException | ||||
|                         ("Cannot connect. All connections are in use."); | ||||
|              | ||||
|             if(GuacamoleProperties.getProperty( | ||||
|                     MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS, true) | ||||
|                     && activeConnectionMap.isConnectionGroupUserActive(group.getConnectionGroupID(), userID)) | ||||
|                 throw new GuacamoleClientTooManyException | ||||
|                         ("Cannot connect. Connection group already in use by this user."); | ||||
|  | ||||
|             // Get the connection  | ||||
|             MySQLConnection connection = connectionService | ||||
|                     .retrieveConnection(leastUsedConnectionID, userID); | ||||
|              | ||||
|             // Connect to the connection | ||||
|             return connectionService.connect(connection, info, userID, group.getConnectionGroupID()); | ||||
|  | ||||
|         } | ||||
|              | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|   | ||||
| @@ -322,46 +322,49 @@ public class ConnectionService { | ||||
|             GuacamoleClientInformation info, int userID, Integer connectionGroupID) | ||||
|         throws GuacamoleException { | ||||
|  | ||||
|         // If the given connection is active, and multiple simultaneous | ||||
|         // connections are not allowed, disallow connection | ||||
|         if(GuacamoleProperties.getProperty( | ||||
|                 MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false) | ||||
|                 && activeConnectionMap.isActive(connection.getConnectionID())) | ||||
|             throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use."); | ||||
|          | ||||
|         if(GuacamoleProperties.getProperty( | ||||
|                 MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS, true) | ||||
|                 && activeConnectionMap.isConnectionUserActive(connection.getConnectionID(), userID)) | ||||
|             throw new GuacamoleClientTooManyException | ||||
|                     ("Cannot connect. Connection already in use by this user."); | ||||
|         synchronized (activeConnectionMap) { | ||||
|  | ||||
|         // Get guacd connection information | ||||
|         String host = GuacamoleProperties.getRequiredProperty(GuacamoleProperties.GUACD_HOSTNAME); | ||||
|         int port = GuacamoleProperties.getRequiredProperty(GuacamoleProperties.GUACD_PORT); | ||||
|             // If the given connection is active, and multiple simultaneous | ||||
|             // connections are not allowed, disallow connection | ||||
|             if(GuacamoleProperties.getProperty( | ||||
|                     MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false) | ||||
|                     && activeConnectionMap.isActive(connection.getConnectionID())) | ||||
|                 throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use."); | ||||
|              | ||||
|             if(GuacamoleProperties.getProperty( | ||||
|                     MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS, true) | ||||
|                     && activeConnectionMap.isConnectionUserActive(connection.getConnectionID(), userID)) | ||||
|                 throw new GuacamoleClientTooManyException | ||||
|                         ("Cannot connect. Connection already in use by this user."); | ||||
|  | ||||
|         // Get socket | ||||
|         GuacamoleSocket socket; | ||||
|         if (GuacamoleProperties.getProperty(GuacamoleProperties.GUACD_SSL, false)) | ||||
|             socket = new ConfiguredGuacamoleSocket( | ||||
|                 new SSLGuacamoleSocket(host, port), | ||||
|                 connection.getConfiguration(), info | ||||
|             ); | ||||
|         else | ||||
|             socket = new ConfiguredGuacamoleSocket( | ||||
|                 new InetGuacamoleSocket(host, port), | ||||
|                 connection.getConfiguration(), info | ||||
|             ); | ||||
|             // Get guacd connection information | ||||
|             String host = GuacamoleProperties.getRequiredProperty(GuacamoleProperties.GUACD_HOSTNAME); | ||||
|             int port = GuacamoleProperties.getRequiredProperty(GuacamoleProperties.GUACD_PORT); | ||||
|  | ||||
|         // Mark this connection as active | ||||
|         int historyID = activeConnectionMap.openConnection(connection.getConnectionID(),  | ||||
|                 userID, connectionGroupID); | ||||
|             // Get socket | ||||
|             GuacamoleSocket socket; | ||||
|             if (GuacamoleProperties.getProperty(GuacamoleProperties.GUACD_SSL, false)) | ||||
|                 socket = new ConfiguredGuacamoleSocket( | ||||
|                     new SSLGuacamoleSocket(host, port), | ||||
|                     connection.getConfiguration(), info | ||||
|                 ); | ||||
|             else | ||||
|                 socket = new ConfiguredGuacamoleSocket( | ||||
|                     new InetGuacamoleSocket(host, port), | ||||
|                     connection.getConfiguration(), info | ||||
|                 ); | ||||
|  | ||||
|         // Return new MySQLGuacamoleSocket | ||||
|         MySQLGuacamoleSocket mySQLGuacamoleSocket = mySQLGuacamoleSocketProvider.get(); | ||||
|         mySQLGuacamoleSocket.init(socket, connection.getConnectionID(), userID,  | ||||
|                 historyID, connectionGroupID); | ||||
|          | ||||
|         return mySQLGuacamoleSocket; | ||||
|             // Mark this connection as active | ||||
|             int historyID = activeConnectionMap.openConnection(connection.getConnectionID(),  | ||||
|                     userID, connectionGroupID); | ||||
|  | ||||
|                 // Return new MySQLGuacamoleSocket | ||||
|             MySQLGuacamoleSocket mySQLGuacamoleSocket = mySQLGuacamoleSocketProvider.get(); | ||||
|             mySQLGuacamoleSocket.init(socket, historyID, connectionGroupID); | ||||
|                  | ||||
|             return mySQLGuacamoleSocket; | ||||
|  | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user