diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 9af44f6a1b..4636c61367 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -74,6 +74,14 @@ } ] }, + { + "name": "maximum_user_capacity", + "label": "Maximum User Capacity", + "help": "The limit on how many avatars can be connected at once. 0 means no limit.", + "placeholder": "0", + "default": "0", + "advanced": false + }, { "name": "allowed_editors", "type": "table", diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 7af9ffd85c..2e3505dd4d 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -44,6 +44,7 @@ const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.io"; const QString ALLOWED_USERS_SETTINGS_KEYPATH = "security.allowed_users"; +const QString MAXIMUM_USER_CAPACITY = "security.maximum_user_capacity"; const QString ALLOWED_EDITORS_SETTINGS_KEYPATH = "security.allowed_editors"; @@ -667,9 +668,22 @@ void DomainServer::handleConnectRequest(const QByteArray& packet, const HifiSock } +unsigned int DomainServer::countConnectedUsers() { + unsigned int result = 0; + auto nodeList = DependencyManager::get(); + nodeList->eachNode([&](const SharedNodePointer& otherNode){ + if (otherNode->getType() == NodeType::Agent) { + result++; + } + }); + return result; +} + + bool DomainServer::shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature, const HifiSockAddr& senderSockAddr) { + const QVariant* allowedUsersVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ALLOWED_USERS_SETTINGS_KEYPATH); QStringList allowedUsers = allowedUsersVariant ? allowedUsersVariant->toStringList() : QStringList(); @@ -679,6 +693,18 @@ bool DomainServer::shouldAllowConnectionFromNode(const QString& username, || senderSockAddr.getAddress() == QHostAddress::LocalHost) { return true; } + + const QVariant* maximumUserCapacityVariant = valueForKeyPath(_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY); + unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0; + if (maximumUserCapacity > 0) { + unsigned int connectedUsers = countConnectedUsers(); + if (connectedUsers >= maximumUserCapacity) { + // too many users, deny the new connection. + qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, denying new connection."; + return false; + } + qDebug() << connectedUsers << "/" << maximumUserCapacity << "users connected, perhaps allowing new connection."; + } if (allowedUsers.count() > 0) { if (allowedUsers.contains(username, Qt::CaseInsensitive)) { diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index f910534eb1..7052cd65a8 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -83,6 +83,7 @@ private: void processDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); void handleConnectRequest(const QByteArray& packet, const HifiSockAddr& senderSockAddr); + unsigned int countConnectedUsers(); bool shouldAllowConnectionFromNode(const QString& username, const QByteArray& usernameSignature, const HifiSockAddr& senderSockAddr);