diff --git a/cockatrice/src/tab_game.cpp b/cockatrice/src/tab_game.cpp index 596a4e4b..fd6c76f0 100644 --- a/cockatrice/src/tab_game.cpp +++ b/cockatrice/src/tab_game.cpp @@ -296,7 +296,7 @@ void TabGame::retranslateUi() aConcede->setText(tr("&Concede")); aConcede->setShortcut(tr("F2")); aLeaveGame->setText(tr("&Leave game")); - aLeaveGame->setShortcut(tr("Esc")); + aLeaveGame->setShortcut(tr("Ctrl+Q")); sayLabel->setText(tr("&Say:")); cardInfo->retranslateUi(); diff --git a/common/server.cpp b/common/server.cpp index 064f7519..67e1172a 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -112,24 +112,28 @@ void Server::broadcastRoomUpdate() delete event; } -void Server::gameCreated(Server_Game *game) -{ - QMutexLocker locker(&serverMutex); - games.insert(game->getGameId(), game); -} - -void Server::gameClosing(int gameId) -{ - QMutexLocker locker(&serverMutex); - qDebug("Server::gameClosing"); - games.remove(gameId); -} - void Server::addRoom(Server_Room *newRoom) { QMutexLocker locker(&serverMutex); rooms.insert(newRoom->getId(), newRoom); connect(newRoom, SIGNAL(roomInfoChanged()), this, SLOT(broadcastRoomUpdate())); - connect(newRoom, SIGNAL(gameCreated(Server_Game *)), this, SLOT(gameCreated(Server_Game *))); - connect(newRoom, SIGNAL(gameClosing(int)), this, SLOT(gameClosing(int))); +} + +int Server::getUsersCount() const +{ + QMutexLocker locker(&serverMutex); + return users.size(); +} + +int Server::getGamesCount() const +{ + int result = 0; + QMutexLocker locker(&serverMutex); + QMapIterator roomIterator(rooms); + while (roomIterator.hasNext()) { + Server_Room *room = roomIterator.next().value(); + QMutexLocker roomLocker(&room->roomMutex); + result += room->getGames().size(); + } + return result; } diff --git a/common/server.h b/common/server.h index 70ef8b02..e401ca80 100644 --- a/common/server.h +++ b/common/server.h @@ -19,15 +19,12 @@ class Server : public QObject signals: void pingClockTimeout(); private slots: - void gameCreated(Server_Game *game); - void gameClosing(int gameId); void broadcastRoomUpdate(); public: mutable QMutex serverMutex; Server(QObject *parent = 0); ~Server(); AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password); - QList getGames() const { return games.values(); } const QMap &getRooms() { return rooms; } int getNextGameId() { return nextGameId++; } @@ -42,12 +39,12 @@ public: virtual int getMessageCountingInterval() const { return 0; } virtual int getMaxMessageCountPerInterval() const { return 0; } virtual int getMaxMessageSizePerInterval() const { return 0; } + virtual int getMaxGamesPerUser() const { return 0; } virtual QMap getBuddyList(const QString &name) = 0; virtual QMap getIgnoreList(const QString &name) = 0; virtual bool getUserBanned(Server_ProtocolHandler * /*client*/, const QString & /*userName*/) const { return false; } protected: - QMap games; QList clients; QMap users; QMap rooms; @@ -55,6 +52,8 @@ protected: virtual bool userExists(const QString &user) = 0; virtual AuthenticationResult checkUserPassword(const QString &user, const QString &password) = 0; virtual ServerInfo_User *getUserData(const QString &name) = 0; + int getUsersCount() const; + int getGamesCount() const; int nextGameId; void addRoom(Server_Room *newRoom); }; diff --git a/common/server_game.cpp b/common/server_game.cpp index 3ef78a0f..6a206bb7 100644 --- a/common/server_game.cpp +++ b/common/server_game.cpp @@ -44,6 +44,7 @@ Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QS Server_Game::~Server_Game() { + QMutexLocker roomLocker(&room->roomMutex); QMutexLocker locker(&gameMutex); sendGameEvent(new Event_GameClosed); @@ -53,7 +54,7 @@ Server_Game::~Server_Game() delete playerIterator.next().value(); players.clear(); - emit gameClosing(); + room->removeGame(this); delete creatorInfo; qDebug("Server_Game destructor"); } @@ -233,6 +234,7 @@ Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spec void Server_Game::removePlayer(Server_Player *player) { + QMutexLocker roomLocker(&room->roomMutex); QMutexLocker locker(&gameMutex); players.remove(player->getPlayerId()); @@ -281,6 +283,7 @@ void Server_Game::removeArrowsToPlayer(Server_Player *player) bool Server_Game::kickPlayer(int playerId) { + QMutexLocker roomLocker(&room->roomMutex); QMutexLocker locker(&gameMutex); Server_Player *playerToKick = players.value(playerId); diff --git a/common/server_game.h b/common/server_game.h index d2af449b..2042a444 100644 --- a/common/server_game.h +++ b/common/server_game.h @@ -53,7 +53,6 @@ private: int secondsElapsed; QTimer *pingClock; signals: - void gameClosing(); void sigStartGameIfReady(); private slots: void pingClockTimeout(); diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 355ccdaf..70e8c1eb 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -276,37 +276,21 @@ ResponseCode Server_ProtocolHandler::cmdLogin(Command_Login *cmd, CommandContain enqueueProtocolItem(new Event_ServerMessage(server->getLoginMessage())); + QList _buddyList, _ignoreList; if (authState == PasswordRight) { buddyList = server->getBuddyList(userInfo->getName()); + + QMapIterator buddyIterator(buddyList); + while (buddyIterator.hasNext()) + _buddyList.append(new ServerInfo_User(buddyIterator.next().value())); + ignoreList = server->getIgnoreList(userInfo->getName()); - // This might not scale very well. Use an extra QMap if it becomes a problem. - QMutexLocker serverLocker(&server->serverMutex); - QMutexLocker gameListLocker(&gameListMutex); - const QList &serverGames = server->getGames(); - for (int i = 0; i < serverGames.size(); ++i) { - QMutexLocker gameLocker(&serverGames[i]->gameMutex); - const QList &gamePlayers = serverGames[i]->getPlayers().values(); - for (int j = 0; j < gamePlayers.size(); ++j) - if (gamePlayers[j]->getUserInfo()->getName() == userInfo->getName()) { - gamePlayers[j]->setProtocolHandler(this); - games.insert(serverGames[i]->getGameId(), QPair(serverGames[i], gamePlayers[j])); - - enqueueProtocolItem(new Event_GameJoined(serverGames[i]->getGameId(), serverGames[i]->getDescription(), gamePlayers[j]->getPlayerId(), gamePlayers[j]->getSpectator(), serverGames[i]->getSpectatorsCanTalk(), serverGames[i]->getSpectatorsSeeEverything(), true)); - enqueueProtocolItem(GameEventContainer::makeNew(new Event_GameStateChanged(serverGames[i]->getGameStarted(), serverGames[i]->getActivePlayer(), serverGames[i]->getActivePhase(), serverGames[i]->getGameState(gamePlayers[j])), serverGames[i]->getGameId())); - } - } + QMapIterator ignoreIterator(ignoreList); + while (ignoreIterator.hasNext()) + _ignoreList.append(new ServerInfo_User(ignoreIterator.next().value())); } - QList _buddyList; - QMapIterator buddyIterator(buddyList); - while (buddyIterator.hasNext()) - _buddyList.append(new ServerInfo_User(buddyIterator.next().value())); - QList _ignoreList; - QMapIterator ignoreIterator(ignoreList); - while (ignoreIterator.hasNext()) - _ignoreList.append(new ServerInfo_User(ignoreIterator.next().value())); - cont->setResponse(new Response_Login(cont->getCmdId(), RespOk, new ServerInfo_User(userInfo, true), _buddyList, _ignoreList)); return RespNothing; } @@ -373,12 +357,32 @@ ResponseCode Server_ProtocolHandler::cmdJoinRoom(Command_JoinRoom *cmd, CommandC Server_Room *r = server->getRooms().value(cmd->getRoomId(), 0); if (!r) return RespNameNotFound; - + + QMutexLocker roomLocker(&r->roomMutex); r->addClient(this); rooms.insert(r->getId(), r); enqueueProtocolItem(new Event_RoomSay(r->getId(), QString(), r->getJoinMessage())); + // This might not scale very well. Use an extra QMap if it becomes a problem. + QMutexLocker gameListLocker(&gameListMutex); + QMapIterator gameIterator(r->getGames()); + while (gameIterator.hasNext()) { + Server_Game *game = gameIterator.next().value(); + QMutexLocker gameLocker(&game->gameMutex); + const QList &gamePlayers = game->getPlayers().values(); + for (int j = 0; j < gamePlayers.size(); ++j) + if (gamePlayers[j]->getUserInfo()->getName() == userInfo->getName()) { + gamePlayers[j]->setProtocolHandler(this); + games.insert(game->getGameId(), QPair(game, gamePlayers[j])); + + enqueueProtocolItem(new Event_GameJoined(game->getGameId(), game->getDescription(), gamePlayers[j]->getPlayerId(), gamePlayers[j]->getSpectator(), game->getSpectatorsCanTalk(), game->getSpectatorsSeeEverything(), true)); + enqueueProtocolItem(GameEventContainer::makeNew(new Event_GameStateChanged(game->getGameStarted(), game->getActivePlayer(), game->getActivePhase(), game->getGameState(gamePlayers[j])), game->getGameId())); + + break; + } + } + cont->setResponse(new Response_JoinRoom(cont->getCmdId(), RespOk, r->getInfo(true))); return RespNothing; } @@ -436,6 +440,10 @@ ResponseCode Server_ProtocolHandler::cmdCreateGame(Command_CreateGame *cmd, Comm { if (authState == PasswordWrong) return RespLoginNeeded; + + if (server->getMaxGamesPerUser() > 0) + if (room->getGamesCreatedByUser(userInfo->getName()) >= server->getMaxGamesPerUser()) + return RespContextError; QList gameTypes; QList gameTypeList = cmd->getGameTypes(); diff --git a/common/server_room.cpp b/common/server_room.cpp index 7117b798..75aa10ed 100644 --- a/common/server_room.cpp +++ b/common/server_room.cpp @@ -87,26 +87,33 @@ Server_Game *Server_Room::createGame(const QString &description, const QString & // This mutex needs to be unlocked by the caller. newGame->gameMutex.lock(); games.insert(newGame->getGameId(), newGame); - connect(newGame, SIGNAL(gameClosing()), this, SLOT(removeGame())); broadcastGameListUpdate(newGame); - emit gameCreated(newGame); emit roomInfoChanged(); return newGame; } -void Server_Room::removeGame() +void Server_Room::removeGame(Server_Game *game) { - QMutexLocker locker(&roomMutex); - - Server_Game *game = static_cast(sender()); - QMutexLocker gameLocker(&game->gameMutex); + // No need to lock roomMutex or gameMutex. This method is only + // called from ~Server_Game, which locks both mutexes anyway beforehand. broadcastGameListUpdate(game); games.remove(game->getGameId()); - emit gameClosing(game->getGameId()); emit roomInfoChanged(); } + +int Server_Room::getGamesCreatedByUser(const QString &userName) const +{ + QMutexLocker locker(&roomMutex); + + QMapIterator gamesIterator(games); + int result = 0; + while (gamesIterator.hasNext()) + if (gamesIterator.next().value()->getCreatorInfo()->getName() == userName) + ++result; + return result; +} diff --git a/common/server_room.h b/common/server_room.h index 10f6c255..e5f4867c 100644 --- a/common/server_room.h +++ b/common/server_room.h @@ -18,8 +18,6 @@ class Server_Room : public QObject, public QList { Q_OBJECT signals: void roomInfoChanged(); - void gameCreated(Server_Game *game); - void gameClosing(int gameId); private: int id; QString name; @@ -28,8 +26,6 @@ private: QString joinMessage; QStringList gameTypes; QMap games; -private slots: - void removeGame(); public: mutable QMutex roomMutex; Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent); @@ -41,12 +37,14 @@ public: const QMap &getGames() const { return games; } Server *getServer() const; ServerInfo_Room *getInfo(bool complete) const; + int getGamesCreatedByUser(const QString &name) const; void addClient(Server_ProtocolHandler *client); void removeClient(Server_ProtocolHandler *client); void say(Server_ProtocolHandler *client, const QString &s); void broadcastGameListUpdate(Server_Game *game); Server_Game *createGame(const QString &description, const QString &password, int maxPlayers, const QList &_gameTypes, bool onlyBuddies, bool onlyRegistered, bool spectatorsAllowed, bool spectatorsNeedPassword, bool spectatorsCanTalk, bool spectatorsSeeEverything, Server_ProtocolHandler *creator); + void removeGame(Server_Game *game); void sendRoomEvent(RoomEvent *event); }; diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index 37e88a75..72647bc4 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -35,3 +35,4 @@ max_users_per_address=4 message_counting_interval=10 max_message_size_per_interval=1000 max_message_count_per_interval=10 +max_games_per_user=5 diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index cc8fb5b3..3e36a808 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -102,6 +102,7 @@ Servatrice::Servatrice(QSettings *_settings, QObject *parent) messageCountingInterval = settings->value("security/message_counting_interval").toInt(); maxMessageCountPerInterval = settings->value("security/max_message_count_per_interval").toInt(); maxMessageSizePerInterval = settings->value("security/max_message_size_per_interval").toInt(); + maxGamesPerUser = settings->value("security/max_games_per_user").toInt(); } Servatrice::~Servatrice() @@ -357,9 +358,9 @@ void Servatrice::statusUpdate() query.prepare("insert into " + dbPrefix + "_uptime (id_server, timest, uptime, users_count, games_count) values(:id, NOW(), :uptime, :users_count, :games_count)"); query.bindValue(":id", serverId); query.bindValue(":uptime", uptime); - query.bindValue(":users_count", users.size()); - query.bindValue(":games_count", games.size()); + query.bindValue(":users_count", getUsersCount()); + query.bindValue(":games_count", getGamesCount()); execSqlQuery(query); } -const QString Servatrice::versionString = "Servatrice 0.20110406"; +const QString Servatrice::versionString = "Servatrice 0.20110421"; diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index 0296a903..9498d8a1 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -65,6 +65,7 @@ public: int getMessageCountingInterval() const { return messageCountingInterval; } int getMaxMessageCountPerInterval() const { return maxMessageCountPerInterval; } int getMaxMessageSizePerInterval() const { return maxMessageSizePerInterval; } + int getMaxGamesPerUser() const { return maxGamesPerUser; } QString getDbPrefix() const { return dbPrefix; } void updateLoginMessage(); ServerInfo_User *getUserData(const QString &name); @@ -88,7 +89,7 @@ private: QList > addressBanList; QList > nameBanList; int maxGameInactivityTime, maxPlayerInactivityTime; - int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval; + int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval, maxGamesPerUser; ServerInfo_User *evalUserQueryResult(const QSqlQuery &query, bool complete); };