From eb9ca58fd048c586b763522586edabac422799aa Mon Sep 17 00:00:00 2001 From: woogerboy21 Date: Thu, 30 Jul 2015 16:38:02 -0400 Subject: [PATCH] Updated pingClockTimeout to account for adjustments in client keep alive settings value. Changed the default value for the client keep alive variable back to 1 (since that is what the setting is if the value is not found in the configuration ini file). --- common/server.h | 17 ++-- common/server_protocolhandler.cpp | 157 ++++++++++++++++-------------- servatrice/servatrice.ini.example | 4 +- servatrice/src/servatrice.cpp | 5 +- servatrice/src/servatrice.h | 11 ++- 5 files changed, 102 insertions(+), 92 deletions(-) diff --git a/common/server.h b/common/server.h index ad17bc53..a32c88fd 100644 --- a/common/server.h +++ b/common/server.h @@ -47,15 +47,16 @@ public: AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reason, int &secondsLeft); const QMap &getRooms() { return rooms; } - + Server_AbstractUserInterface *findUser(const QString &userName) const; const QMap &getUsers() const { return users; } const QMap &getUsersBySessionId() const { return usersBySessionId; } void addClient(Server_ProtocolHandler *player); void removeClient(Server_ProtocolHandler *player); virtual QString getLoginMessage() const { return QString(); } - + virtual bool getGameShouldPing() const { return false; } + virtual int getPingClockInterval() const { return 0; } virtual int getMaxGameInactivityTime() const { return 9999999; } virtual int getMaxPlayerInactivityTime() const { return 9999999; } virtual int getMessageCountingInterval() const { return 0; } @@ -69,18 +70,18 @@ public: Server_DatabaseInterface *getDatabaseInterface() const; int getNextLocalGameId() { QMutexLocker locker(&nextLocalGameIdMutex); return ++nextLocalGameId; } - + void sendIsl_Response(const Response &item, int serverId = -1, qint64 sessionId = -1); void sendIsl_SessionEvent(const SessionEvent &item, int serverId = -1, qint64 sessionId = -1); void sendIsl_GameEventContainer(const GameEventContainer &item, int serverId = -1, qint64 sessionId = -1); void sendIsl_RoomEvent(const RoomEvent &item, int serverId = -1, qint64 sessionId = -1); void sendIsl_GameCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId, int playerId); void sendIsl_RoomCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId); - + void addExternalUser(const ServerInfo_User &userInfo); void removeExternalUser(const QString &userName); const QMap &getExternalUsers() const { return externalUsers; } - + void addPersistentPlayer(const QString &userName, int roomId, int gameId, int playerId); void removePersistentPlayer(const QString &userName, int roomId, int gameId, int playerId); QList getPersistentPlayerReferences(const QString &userName) const; @@ -90,7 +91,7 @@ private: mutable QReadWriteLock persistentPlayersLock; int nextLocalGameId; QMutex nextLocalGameIdMutex; -protected slots: +protected slots: void externalUserJoined(const ServerInfo_User &userInfo); void externalUserLeft(const QString &userName); void externalRoomUserJoined(int roomId, const ServerInfo_User &userInfo); @@ -101,7 +102,7 @@ protected slots: void externalGameCommandContainerReceived(const CommandContainer &cont, int playerId, int serverId, qint64 sessionId); void externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId); void externalResponseReceived(const Response &resp, qint64 sessionId); - + virtual void doSendIslMessage(const IslMessage & /* msg */, int /* serverId */) { } protected: void prepareDestroy(); @@ -113,7 +114,7 @@ protected: QMap externalUsers; QMap rooms; QMap databaseInterfaces; - + int getUsersCount() const; int getGamesCount() const; void addRoom(Server_Room *newRoom); diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 7df87189..ef1150f7 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -45,18 +45,18 @@ void Server_ProtocolHandler::prepareDestroy() if (deleted) return; deleted = true; - + QMapIterator roomIterator(rooms); while (roomIterator.hasNext()) roomIterator.next().value()->removeClient(this); - + QMap > tempGames(getGames()); - + server->roomsLock.lockForRead(); QMapIterator > gameIterator(tempGames); while (gameIterator.hasNext()) { gameIterator.next(); - + Server_Room *r = server->getRooms().value(gameIterator.value().first); if (!r) continue; @@ -73,16 +73,16 @@ void Server_ProtocolHandler::prepareDestroy() r->gamesLock.unlock(); continue; } - + p->disconnectClient(); - + g->gameMutex.unlock(); r->gamesLock.unlock(); } server->roomsLock.unlock(); - + server->removeClient(this); - + deleteLater(); } @@ -91,7 +91,7 @@ void Server_ProtocolHandler::sendProtocolItem(const Response &item) ServerMessage msg; msg.mutable_response()->CopyFrom(item); msg.set_message_type(ServerMessage::RESPONSE); - + transmitProtocolItem(msg); } @@ -100,7 +100,7 @@ void Server_ProtocolHandler::sendProtocolItem(const SessionEvent &item) ServerMessage msg; msg.mutable_session_event()->CopyFrom(item); msg.set_message_type(ServerMessage::SESSION_EVENT); - + transmitProtocolItem(msg); } @@ -109,7 +109,7 @@ void Server_ProtocolHandler::sendProtocolItem(const GameEventContainer &item) ServerMessage msg; msg.mutable_game_event_container()->CopyFrom(item); msg.set_message_type(ServerMessage::GAME_EVENT_CONTAINER); - + transmitProtocolItem(msg); } @@ -118,7 +118,7 @@ void Server_ProtocolHandler::sendProtocolItem(const RoomEvent &item) ServerMessage msg; msg.mutable_room_event()->CopyFrom(item); msg.set_message_type(ServerMessage::ROOM_EVENT); - + transmitProtocolItem(msg); } @@ -167,7 +167,7 @@ Response::ResponseCode Server_ProtocolHandler::processRoomCommandContainer(const Server_Room *room = rooms.value(cont.room_id(), 0); if (!room) return Response::RespNotInRoom; - + Response::ResponseCode finalResponseCode = Response::RespOk; for (int i = cont.room_command_size() - 1; i >= 0; --i) { Response::ResponseCode resp = Response::RespInvalidCommand; @@ -206,17 +206,17 @@ Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const if (authState == NotLoggedIn) return Response::RespLoginNeeded; - + QMap > gameMap = getGames(); if (!gameMap.contains(cont.game_id())) return Response::RespNotInRoom; const QPair roomIdAndPlayerId = gameMap.value(cont.game_id()); - + QReadLocker roomsLocker(&server->roomsLock); Server_Room *room = server->getRooms().value(roomIdAndPlayerId.first); if (!room) return Response::RespNotInRoom; - + QReadLocker roomGamesLocker(&room->gamesLock); Server_Game *game = room->getGames().value(cont.game_id()); if (!game) { @@ -231,12 +231,12 @@ Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const } return Response::RespNotInRoom; } - + QMutexLocker gameLocker(&game->gameMutex); Server_Player *player = game->getPlayers().value(roomIdAndPlayerId.second); if (!player) return Response::RespNotInRoom; - + int commandCountingInterval = server->getCommandCountingInterval(); int maxCommandCountPerInterval = server->getMaxCommandCountPerInterval(); GameEventStorage ges; @@ -255,7 +255,7 @@ Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const for (int i = 0; i < commandCountOverTime.size(); ++i) totalCount += commandCountOverTime[i]; - + if (totalCount > maxCommandCountPerInterval) return Response::RespChatFlood; } @@ -266,7 +266,7 @@ Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const finalResponseCode = resp; } ges.sendToGame(game); - + return finalResponseCode; } @@ -283,7 +283,7 @@ Response::ResponseCode Server_ProtocolHandler::processModeratorCommandContainer( const ModeratorCommand &sc = cont.moderator_command(i); const int num = getPbExtension(sc); logDebugMessage(QString::fromStdString(sc.ShortDebugString())); - + resp = processExtendedModeratorCommand(num, sc, rc); if (resp != Response::RespOk) finalResponseCode = resp; @@ -304,7 +304,7 @@ Response::ResponseCode Server_ProtocolHandler::processAdminCommandContainer(cons const AdminCommand &sc = cont.admin_command(i); const int num = getPbExtension(sc); logDebugMessage(QString::fromStdString(sc.ShortDebugString())); - + resp = processExtendedAdminCommand(num, sc, rc); if (resp != Response::RespOk) finalResponseCode = resp; @@ -317,12 +317,12 @@ void Server_ProtocolHandler::processCommandContainer(const CommandContainer &con // Command processing must be disabled after prepareDestroy() has been called. if (deleted) return; - + lastDataReceived = timeRunning; - + ResponseContainer responseContainer(cont.has_cmd_id() ? cont.cmd_id() : -1); Response::ResponseCode finalResponseCode; - + if (cont.game_command_size()) finalResponseCode = processGameCommandContainer(cont, responseContainer); else if (cont.room_command_size()) @@ -335,28 +335,37 @@ void Server_ProtocolHandler::processCommandContainer(const CommandContainer &con finalResponseCode = processAdminCommandContainer(cont, responseContainer); else finalResponseCode = Response::RespInvalidCommand; - + if ((finalResponseCode != Response::RespNothing)) sendResponseContainer(responseContainer, finalResponseCode); } void Server_ProtocolHandler::pingClockTimeout() { + + int cmdcountinterval = server->getCommandCountingInterval(); + int msgcountinterval = server->getMessageCountingInterval(); + int pingclockinterval = server->getPingClockInterval(); + int interval = server->getMessageCountingInterval(); if (interval > 0) { - messageSizeOverTime.prepend(0); - if (messageSizeOverTime.size() > server->getMessageCountingInterval()) - messageSizeOverTime.removeLast(); - messageCountOverTime.prepend(0); - if (messageCountOverTime.size() > server->getMessageCountingInterval()) - messageCountOverTime.removeLast(); + if(pingclockinterval > 0) { + messageSizeOverTime.prepend(0); + if (messageSizeOverTime.size() > (msgcountinterval / pingclockinterval)) + messageSizeOverTime.removeLast(); + messageCountOverTime.prepend(0); + if (messageCountOverTime.size() > (msgcountinterval / pingclockinterval)) + messageCountOverTime.removeLast(); + } } interval = server->getCommandCountingInterval(); if (interval > 0) { - commandCountOverTime.prepend(0); - if (commandCountOverTime.size() > server->getCommandCountingInterval()) - commandCountOverTime.removeLast(); + if (pingclockinterval > 0) { + commandCountOverTime.prepend(0); + if (commandCountOverTime.size() > (cmdcountinterval / pingclockinterval)) + commandCountOverTime.removeLast(); + } } if (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime()) @@ -398,27 +407,27 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd case UserIsInactive: return Response::RespAccountNotActivated; default: authState = res; } - + userName = QString::fromStdString(userInfo->name()); Event_ServerMessage event; event.set_message(server->getLoginMessage().toStdString()); rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event)); - + Response_Login *re = new Response_Login; re->mutable_user_info()->CopyFrom(copyUserInfo(true)); - + if (authState == PasswordRight) { QMapIterator buddyIterator(databaseInterface->getBuddyList(userName)); while (buddyIterator.hasNext()) re->add_buddy_list()->CopyFrom(buddyIterator.next().value()); - + QMapIterator ignoreIterator(databaseInterface->getIgnoreList(userName)); while (ignoreIterator.hasNext()) re->add_ignore_list()->CopyFrom(ignoreIterator.next().value()); } - + joinPersistentGames(rc); - + rc.setResponseExtension(re); return Response::RespOk; } @@ -427,21 +436,21 @@ Response::ResponseCode Server_ProtocolHandler::cmdMessage(const Command_Message { if (authState == NotLoggedIn) return Response::RespLoginNeeded; - + QReadLocker locker(&server->clientsLock); - + QString receiver = QString::fromStdString(cmd.user_name()); Server_AbstractUserInterface *userInterface = server->findUser(receiver); if (!userInterface) return Response::RespNameNotFound; if (databaseInterface->isInIgnoreList(receiver, QString::fromStdString(userInfo->name()))) return Response::RespInIgnoreList; - + Event_UserMessage event; event.set_sender_name(userInfo->name()); event.set_receiver_name(cmd.user_name()); event.set_message(cmd.message()); - + SessionEvent *se = prepareSessionEvent(event); userInterface->sendProtocolItem(*se); rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, se); @@ -455,10 +464,10 @@ Response::ResponseCode Server_ProtocolHandler::cmdGetGamesOfUser(const Command_G { if (authState == NotLoggedIn) return Response::RespLoginNeeded; - + // We don't need to check whether the user is logged in; persistent games should also work. // The client needs to deal with an empty result list. - + Response_GetGamesOfUser *re = new Response_GetGamesOfUser; server->roomsLock.lockForRead(); QMapIterator roomIterator(server->getRooms()); @@ -472,7 +481,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdGetGamesOfUser(const Command_G room->gamesLock.unlock(); } server->roomsLock.unlock(); - + rc.setResponseExtension(re); return Response::RespOk; } @@ -481,22 +490,22 @@ Response::ResponseCode Server_ProtocolHandler::cmdGetUserInfo(const Command_GetU { if (authState == NotLoggedIn) return Response::RespLoginNeeded; - + QString userName = QString::fromStdString(cmd.user_name()); Response_GetUserInfo *re = new Response_GetUserInfo; if (userName.isEmpty()) re->mutable_user_info()->CopyFrom(*userInfo); else { - + QReadLocker locker(&server->clientsLock); - + ServerInfo_User_Container *infoSource = server->findUser(userName); if (!infoSource) return Response::RespNameNotFound; - + re->mutable_user_info()->CopyFrom(infoSource->copyUserInfo(true, false, userInfo->user_level() & ServerInfo_User::IsModerator)); } - + rc.setResponseExtension(re); return Response::RespOk; } @@ -505,13 +514,13 @@ Response::ResponseCode Server_ProtocolHandler::cmdListRooms(const Command_ListRo { if (authState == NotLoggedIn) return Response::RespLoginNeeded; - + Event_ListRooms event; QMapIterator roomIterator(server->getRooms()); while (roomIterator.hasNext()) roomIterator.next().value()->getInfo(*event.add_room_list(), false); rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event)); - + acceptsRoomListChanges = true; return Response::RespOk; } @@ -520,25 +529,25 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinRoom(const Command_JoinRoo { if (authState == NotLoggedIn) return Response::RespLoginNeeded; - + if (rooms.contains(cmd.room_id())) return Response::RespContextError; - + QReadLocker serverLocker(&server->roomsLock); Server_Room *r = server->getRooms().value(cmd.room_id(), 0); if (!r) return Response::RespNameNotFound; - + r->addClient(this); rooms.insert(r->getId(), r); - + Event_RoomSay joinMessageEvent; joinMessageEvent.set_message(r->getJoinMessage().toStdString()); rc.enqueuePostResponseItem(ServerMessage::ROOM_EVENT, r->prepareRoomEvent(joinMessageEvent)); - + Response_JoinRoom *re = new Response_JoinRoom; r->getInfo(*re->mutable_room_info(), true); - + rc.setResponseExtension(re); return Response::RespOk; } @@ -547,7 +556,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUs { if (authState == NotLoggedIn) return Response::RespLoginNeeded; - + Response_ListUsers *re = new Response_ListUsers; server->clientsLock.lockForRead(); QMapIterator userIterator = server->getUsers(); @@ -556,10 +565,10 @@ Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUs QMapIterator extIterator = server->getExternalUsers(); while (extIterator.hasNext()) re->add_user_list()->CopyFrom(extIterator.next().value()->copyUserInfo(false)); - + acceptsUserListChanges = true; server->clientsLock.unlock(); - + rc.setResponseExtension(re); return Response::RespOk; } @@ -574,7 +583,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLeaveRoom(const Command_LeaveR Response::ResponseCode Server_ProtocolHandler::cmdRoomSay(const Command_RoomSay &cmd, Server_Room *room, ResponseContainer & /*rc*/) { QString msg = QString::fromStdString(cmd.message()); - + if (server->getMessageCountingInterval() > 0) { int totalSize = 0, totalCount = 0; if (messageSizeOverTime.isEmpty()) @@ -582,18 +591,18 @@ Response::ResponseCode Server_ProtocolHandler::cmdRoomSay(const Command_RoomSay messageSizeOverTime[0] += msg.size(); for (int i = 0; i < messageSizeOverTime.size(); ++i) totalSize += messageSizeOverTime[i]; - + if (messageCountOverTime.isEmpty()) messageCountOverTime.prepend(0); ++messageCountOverTime[0]; for (int i = 0; i < messageCountOverTime.size(); ++i) totalCount += messageCountOverTime[i]; - + if ((totalSize > server->getMaxMessageSizePerInterval()) || (totalCount > server->getMaxMessageCountPerInterval())) return Response::RespChatFlood; } msg.replace(QChar('\n'), QChar(' ')); - + room->say(QString::fromStdString(userInfo->name()), msg); databaseInterface->logMessage(userInfo->id(), QString::fromStdString(userInfo->name()), QString::fromStdString(userInfo->address()), msg, Server_DatabaseInterface::MessageTargetRoom, room->getId(), room->getName()); @@ -608,23 +617,23 @@ Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_Creat const int gameId = databaseInterface->getNextGameId(); if (gameId == -1) return Response::RespInternalError; - + if (server->getMaxGamesPerUser() > 0) if (room->getGamesCreatedByUser(QString::fromStdString(userInfo->name())) >= server->getMaxGamesPerUser()) return Response::RespContextError; - + QList gameTypes; for (int i = cmd.game_type_ids_size() - 1; i >= 0; --i) gameTypes.append(cmd.game_type_ids(i)); - + QString description = QString::fromStdString(cmd.description()); if (description.size() > 60) description = description.left(60); - + Server_Game *game = new Server_Game(copyUserInfo(false), gameId, description, QString::fromStdString(cmd.password()), cmd.max_players(), gameTypes, cmd.only_buddies(), cmd.only_registered(), cmd.spectators_allowed(), cmd.spectators_need_password(), cmd.spectators_can_talk(), cmd.spectators_see_everything(), room); game->addPlayer(this, rc, false, false); room->addGame(game); - + return Response::RespOk; } @@ -632,6 +641,6 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGam { if (authState == NotLoggedIn) return Response::RespLoginNeeded; - + return room->processJoinGameCommand(cmd, rc, this); } diff --git a/servatrice/servatrice.ini.example b/servatrice/servatrice.ini.example index 7402edfa..f0388863 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -39,8 +39,8 @@ logfile=server.log logfilters="" ; Set the time interval in seconds that servatrice will use to communicate with each connected client -; to verify the client has not timed out. Defaults is 5 seconds -clientkeepalive=5 +; to verify the client has not timed out. Defaults is 1 seconds +clientkeepalive=1 ; Maximum time in seconds a player can stay inactive with there client not even responding to pings, before is ; considered disconnected; default is 15 diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index b0d3d581..d30a8aaa 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -274,7 +274,7 @@ bool Servatrice::initServer() maxGameInactivityTime = settingsCache->value("game/max_game_inactivity_time", 120).toInt(); maxPlayerInactivityTime = settingsCache->value("server/max_player_inactivity_time", 15).toInt(); - + pingClockInterval = settingsCache->value("server/clientkeepalive", 1).toInt(); maxUsersPerAddress = settingsCache->value("security/max_users_per_address", 4).toInt(); messageCountingInterval = settingsCache->value("security/message_counting_interval", 10).toInt(); maxMessageCountPerInterval = settingsCache->value("security/max_message_count_per_interval", 15).toInt(); @@ -343,10 +343,9 @@ bool Servatrice::initServer() return false; } - int clientkeepalive = settingsCache->value("server/clientkeepalive", 1).toInt(); pingClock = new QTimer(this); connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout())); - pingClock->start(clientkeepalive * 1000); + pingClock->start(pingClockInterval * 1000); int statusUpdateTime = settingsCache->value("server/statusupdate", 15000).toInt(); statusUpdateClock = new QTimer(this); diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index 717e5ab8..a0421cd5 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -83,7 +83,7 @@ public: QHostAddress address; int gamePort; int controlPort; - + ServerProperties(int _id, const QSslCertificate &_cert, const QString &_hostname, const QHostAddress &_address, int _gamePort, int _controlPort) : id(_id), cert(_cert), hostname(_hostname), address(_address), gamePort(_gamePort), controlPort(_controlPort) { } }; @@ -115,17 +115,17 @@ private: QMutex txBytesMutex, rxBytesMutex; quint64 txBytes, rxBytes; int maxGameInactivityTime, maxPlayerInactivityTime; - int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval, maxGamesPerUser, commandCountingInterval, maxCommandCountPerInterval; + int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval, maxGamesPerUser, commandCountingInterval, maxCommandCountPerInterval, pingClockInterval; QString shutdownReason; int shutdownMinutes; QTimer *shutdownTimer; bool isFirstShutdownMessage; - + mutable QMutex serverListMutex; QList serverList; void updateServerList(); - + QMap islInterfaces; public slots: void scheduleShutdown(const QString &reason, int minutes); @@ -137,6 +137,7 @@ public: QString getServerName() const { return serverName; } QString getLoginMessage() const { QMutexLocker locker(&loginMessageMutex); return loginMessage; } bool getGameShouldPing() const { return true; } + int getPingClockInterval() const { return pingClockInterval; } int getMaxGameInactivityTime() const { return maxGameInactivityTime; } int getMaxPlayerInactivityTime() const { return maxPlayerInactivityTime; } int getMaxUsersPerAddress() const { return maxUsersPerAddress; } @@ -154,7 +155,7 @@ public: void incTxBytes(quint64 num); void incRxBytes(quint64 num); void addDatabaseInterface(QThread *thread, Servatrice_DatabaseInterface *databaseInterface); - + bool islConnectionExists(int serverId) const; void addIslInterface(int serverId, IslInterface *interface); void removeIslInterface(int serverId);