diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index ee1f3c59..4d6ff76a 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -262,8 +262,8 @@ void MainWindow::loginError(Response::ResponseCode r, QString reasonStr, quint32 QMessageBox::critical(this, tr("Error"), tr("Invalid username.")); break; case Response::RespRegistrationRequired: - QMessageBox::critical(this, tr("Error"), tr("This server requires user registration.")); - break; + QMessageBox::critical(this, tr("Error"), tr("This server requires user registration.")); + break; default: QMessageBox::critical(this, tr("Error"), tr("Unknown login error: %1").arg(static_cast(r))); } diff --git a/common/server.cpp b/common/server.cpp index 7603b0b8..c4d81220 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -37,18 +37,18 @@ #include Server::Server(bool _threaded, QObject *parent) - : QObject(parent), threaded(_threaded), nextLocalGameId(0) + : QObject(parent), threaded(_threaded), nextLocalGameId(0) { - qRegisterMetaType("ServerInfo_Game"); - qRegisterMetaType("ServerInfo_Room"); - qRegisterMetaType("ServerInfo_User"); - qRegisterMetaType("CommandContainer"); - qRegisterMetaType("Response"); - qRegisterMetaType("GameEventContainer"); - qRegisterMetaType("IslMessage"); - qRegisterMetaType("Command_JoinGame"); - - connect(this, SIGNAL(sigSendIslMessage(IslMessage, int)), this, SLOT(doSendIslMessage(IslMessage, int)), Qt::QueuedConnection); + qRegisterMetaType("ServerInfo_Game"); + qRegisterMetaType("ServerInfo_Room"); + qRegisterMetaType("ServerInfo_User"); + qRegisterMetaType("CommandContainer"); + qRegisterMetaType("Response"); + qRegisterMetaType("GameEventContainer"); + qRegisterMetaType("IslMessage"); + qRegisterMetaType("Command_JoinGame"); + + connect(this, SIGNAL(sigSendIslMessage(IslMessage, int)), this, SLOT(doSendIslMessage(IslMessage, int)), Qt::QueuedConnection); } Server::~Server() @@ -57,540 +57,540 @@ Server::~Server() void Server::prepareDestroy() { - // dirty :( - if (threaded) { - clientsLock.lockForRead(); - for (int i = 0; i < clients.size(); ++i) - QMetaObject::invokeMethod(clients.at(i), "prepareDestroy", Qt::QueuedConnection); - clientsLock.unlock(); - - bool done = false; - - class SleeperThread : public QThread - { - public: - static void msleep(unsigned long msecs) { QThread::usleep(msecs); } - }; + // dirty :( + if (threaded) { + clientsLock.lockForRead(); + for (int i = 0; i < clients.size(); ++i) + QMetaObject::invokeMethod(clients.at(i), "prepareDestroy", Qt::QueuedConnection); + clientsLock.unlock(); + + bool done = false; + + class SleeperThread : public QThread + { + public: + static void msleep(unsigned long msecs) { QThread::usleep(msecs); } + }; - do { - SleeperThread::msleep(10); - clientsLock.lockForRead(); - if (clients.isEmpty()) - done = true; - clientsLock.unlock(); - } while (!done); - } else { - // no locking is needed in unthreaded mode - while (!clients.isEmpty()) - clients.first()->prepareDestroy(); - } - - roomsLock.lockForWrite(); - QMapIterator roomIterator(rooms); - while (roomIterator.hasNext()) - delete roomIterator.next().value(); - rooms.clear(); - roomsLock.unlock(); + do { + SleeperThread::msleep(10); + clientsLock.lockForRead(); + if (clients.isEmpty()) + done = true; + clientsLock.unlock(); + } while (!done); + } else { + // no locking is needed in unthreaded mode + while (!clients.isEmpty()) + clients.first()->prepareDestroy(); + } + + roomsLock.lockForWrite(); + QMapIterator roomIterator(rooms); + while (roomIterator.hasNext()) + delete roomIterator.next().value(); + rooms.clear(); + roomsLock.unlock(); } void Server::setDatabaseInterface(Server_DatabaseInterface *_databaseInterface) { - connect(this, SIGNAL(endSession(qint64)), _databaseInterface, SLOT(endSession(qint64))); - databaseInterfaces.insert(QThread::currentThread(), _databaseInterface); + connect(this, SIGNAL(endSession(qint64)), _databaseInterface, SLOT(endSession(qint64))); + databaseInterfaces.insert(QThread::currentThread(), _databaseInterface); } Server_DatabaseInterface *Server::getDatabaseInterface() const { - return databaseInterfaces.value(QThread::currentThread()); + return databaseInterfaces.value(QThread::currentThread()); } AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr, int &secondsLeft) { - if (name.size() > 35) - name = name.left(35); - - Server_DatabaseInterface *databaseInterface = getDatabaseInterface(); - - QWriteLocker locker(&clientsLock); - - AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft); - if ((authState == NotLoggedIn) || (authState == UserIsBanned || authState == UsernameInvalid)) - return authState; - - ServerInfo_User data = databaseInterface->getUserData(name, true); - data.set_address(session->getAddress().toStdString()); - name = QString::fromStdString(data.name()); // Compensate for case indifference - - databaseInterface->lockSessionTables(); - - if (authState == PasswordRight) { - if (users.contains(name) || databaseInterface->userSessionExists(name)) { - qDebug("Login denied: would overwrite old session"); - databaseInterface->unlockSessionTables(); - return WouldOverwriteOldSession; - } - } else if (authState == UnknownUser) { - // Change user name so that no two users have the same names, - // don't interfere with registered user names though. - QSettings *settings = new QSettings("servatrice.ini", QSettings::IniFormat); - bool requireReg = settings->value("server/regonly").toBool(); - if (requireReg) { - qDebug("Login denied: registration required"); - databaseInterface->unlockSessionTables(); - return RegistrationRequired; - } - - QString tempName = name; - int i = 0; - while (users.contains(tempName) || databaseInterface->userExists(tempName) || databaseInterface->userSessionExists(tempName)) - tempName = name + "_" + QString::number(++i); - name = tempName; - data.set_name(name.toStdString()); - } - - users.insert(name, session); - qDebug() << "Server::loginUser:" << session << "name=" << name; - - data.set_session_id(databaseInterface->startSession(name, session->getAddress())); - databaseInterface->unlockSessionTables(); - - usersBySessionId.insert(data.session_id(), session); - - qDebug() << "session id:" << data.session_id(); - session->setUserInfo(data); - - Event_UserJoined event; - event.mutable_user_info()->CopyFrom(session->copyUserInfo(false)); - SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); - for (int i = 0; i < clients.size(); ++i) - if (clients[i]->getAcceptsUserListChanges()) - clients[i]->sendProtocolItem(*se); - delete se; - - event.mutable_user_info()->CopyFrom(session->copyUserInfo(true, true, true)); - locker.unlock(); - - se = Server_ProtocolHandler::prepareSessionEvent(event); - sendIsl_SessionEvent(*se); - delete se; - - return authState; + if (name.size() > 35) + name = name.left(35); + + Server_DatabaseInterface *databaseInterface = getDatabaseInterface(); + + QWriteLocker locker(&clientsLock); + + AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft); + if ((authState == NotLoggedIn) || (authState == UserIsBanned || authState == UsernameInvalid)) + return authState; + + ServerInfo_User data = databaseInterface->getUserData(name, true); + data.set_address(session->getAddress().toStdString()); + name = QString::fromStdString(data.name()); // Compensate for case indifference + + databaseInterface->lockSessionTables(); + + if (authState == PasswordRight) { + if (users.contains(name) || databaseInterface->userSessionExists(name)) { + qDebug("Login denied: would overwrite old session"); + databaseInterface->unlockSessionTables(); + return WouldOverwriteOldSession; + } + } else if (authState == UnknownUser) { + // Change user name so that no two users have the same names, + // don't interfere with registered user names though. + QSettings *settings = new QSettings("servatrice.ini", QSettings::IniFormat); + bool requireReg = settings->value("authentication/regonly", 0).toBool(); + if (requireReg) { + qDebug("Login denied: registration required"); + databaseInterface->unlockSessionTables(); + return RegistrationRequired; + } + + QString tempName = name; + int i = 0; + while (users.contains(tempName) || databaseInterface->userExists(tempName) || databaseInterface->userSessionExists(tempName)) + tempName = name + "_" + QString::number(++i); + name = tempName; + data.set_name(name.toStdString()); + } + + users.insert(name, session); + qDebug() << "Server::loginUser:" << session << "name=" << name; + + data.set_session_id(databaseInterface->startSession(name, session->getAddress())); + databaseInterface->unlockSessionTables(); + + usersBySessionId.insert(data.session_id(), session); + + qDebug() << "session id:" << data.session_id(); + session->setUserInfo(data); + + Event_UserJoined event; + event.mutable_user_info()->CopyFrom(session->copyUserInfo(false)); + SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); + for (int i = 0; i < clients.size(); ++i) + if (clients[i]->getAcceptsUserListChanges()) + clients[i]->sendProtocolItem(*se); + delete se; + + event.mutable_user_info()->CopyFrom(session->copyUserInfo(true, true, true)); + locker.unlock(); + + se = Server_ProtocolHandler::prepareSessionEvent(event); + sendIsl_SessionEvent(*se); + delete se; + + return authState; } void Server::addPersistentPlayer(const QString &userName, int roomId, int gameId, int playerId) { - QWriteLocker locker(&persistentPlayersLock); - persistentPlayers.insert(userName, PlayerReference(roomId, gameId, playerId)); + QWriteLocker locker(&persistentPlayersLock); + persistentPlayers.insert(userName, PlayerReference(roomId, gameId, playerId)); } void Server::removePersistentPlayer(const QString &userName, int roomId, int gameId, int playerId) { - QWriteLocker locker(&persistentPlayersLock); - persistentPlayers.remove(userName, PlayerReference(roomId, gameId, playerId)); + QWriteLocker locker(&persistentPlayersLock); + persistentPlayers.remove(userName, PlayerReference(roomId, gameId, playerId)); } QList Server::getPersistentPlayerReferences(const QString &userName) const { - QReadLocker locker(&persistentPlayersLock); - return persistentPlayers.values(userName); + QReadLocker locker(&persistentPlayersLock); + return persistentPlayers.values(userName); } Server_AbstractUserInterface *Server::findUser(const QString &userName) const { - // Call this only with clientsLock set. - - Server_AbstractUserInterface *userHandler = users.value(userName); - if (userHandler) - return userHandler; - else - return externalUsers.value(userName); + // Call this only with clientsLock set. + + Server_AbstractUserInterface *userHandler = users.value(userName); + if (userHandler) + return userHandler; + else + return externalUsers.value(userName); } void Server::addClient(Server_ProtocolHandler *client) { - QWriteLocker locker(&clientsLock); - clients << client; + QWriteLocker locker(&clientsLock); + clients << client; } void Server::removeClient(Server_ProtocolHandler *client) { - QWriteLocker locker(&clientsLock); - clients.removeAt(clients.indexOf(client)); - ServerInfo_User *data = client->getUserInfo(); - if (data) { - Event_UserLeft event; - event.set_name(data->name()); - SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); - for (int i = 0; i < clients.size(); ++i) - if (clients[i]->getAcceptsUserListChanges()) - clients[i]->sendProtocolItem(*se); - sendIsl_SessionEvent(*se); - delete se; - - users.remove(QString::fromStdString(data->name())); - qDebug() << "Server::removeClient: name=" << QString::fromStdString(data->name()); - - if (data->has_session_id()) { - const qint64 sessionId = data->session_id(); - usersBySessionId.remove(sessionId); - emit endSession(sessionId); - qDebug() << "closed session id:" << sessionId; - } - } - qDebug() << "Server::removeClient: removed" << (void *) client << ";" << clients.size() << "clients; " << users.size() << "users left"; + QWriteLocker locker(&clientsLock); + clients.removeAt(clients.indexOf(client)); + ServerInfo_User *data = client->getUserInfo(); + if (data) { + Event_UserLeft event; + event.set_name(data->name()); + SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); + for (int i = 0; i < clients.size(); ++i) + if (clients[i]->getAcceptsUserListChanges()) + clients[i]->sendProtocolItem(*se); + sendIsl_SessionEvent(*se); + delete se; + + users.remove(QString::fromStdString(data->name())); + qDebug() << "Server::removeClient: name=" << QString::fromStdString(data->name()); + + if (data->has_session_id()) { + const qint64 sessionId = data->session_id(); + usersBySessionId.remove(sessionId); + emit endSession(sessionId); + qDebug() << "closed session id:" << sessionId; + } + } + qDebug() << "Server::removeClient: removed" << (void *) client << ";" << clients.size() << "clients; " << users.size() << "users left"; } void Server::externalUserJoined(const ServerInfo_User &userInfo) { - // This function is always called from the main thread via signal/slot. - clientsLock.lockForWrite(); - - Server_RemoteUserInterface *newUser = new Server_RemoteUserInterface(this, ServerInfo_User_Container(userInfo)); - externalUsers.insert(QString::fromStdString(userInfo.name()), newUser); - externalUsersBySessionId.insert(userInfo.session_id(), newUser); - - Event_UserJoined event; - event.mutable_user_info()->CopyFrom(userInfo); - - SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); - for (int i = 0; i < clients.size(); ++i) - if (clients[i]->getAcceptsUserListChanges()) - clients[i]->sendProtocolItem(*se); - delete se; - clientsLock.unlock(); - - ResponseContainer rc(-1); - newUser->joinPersistentGames(rc); - newUser->sendResponseContainer(rc, Response::RespNothing); + // This function is always called from the main thread via signal/slot. + clientsLock.lockForWrite(); + + Server_RemoteUserInterface *newUser = new Server_RemoteUserInterface(this, ServerInfo_User_Container(userInfo)); + externalUsers.insert(QString::fromStdString(userInfo.name()), newUser); + externalUsersBySessionId.insert(userInfo.session_id(), newUser); + + Event_UserJoined event; + event.mutable_user_info()->CopyFrom(userInfo); + + SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); + for (int i = 0; i < clients.size(); ++i) + if (clients[i]->getAcceptsUserListChanges()) + clients[i]->sendProtocolItem(*se); + delete se; + clientsLock.unlock(); + + ResponseContainer rc(-1); + newUser->joinPersistentGames(rc); + newUser->sendResponseContainer(rc, Response::RespNothing); } void Server::externalUserLeft(const QString &userName) { - // This function is always called from the main thread via signal/slot. - - clientsLock.lockForWrite(); - Server_AbstractUserInterface *user = externalUsers.take(userName); - externalUsersBySessionId.remove(user->getUserInfo()->session_id()); - clientsLock.unlock(); - - QMap > userGames(user->getGames()); - QMapIterator > userGamesIterator(userGames); - roomsLock.lockForRead(); - while (userGamesIterator.hasNext()) { - userGamesIterator.next(); - Server_Room *room = rooms.value(userGamesIterator.value().first); - if (!room) - continue; - - QReadLocker roomGamesLocker(&room->gamesLock); - Server_Game *game = room->getGames().value(userGamesIterator.key()); - if (!game) - continue; - - QMutexLocker gameLocker(&game->gameMutex); - Server_Player *player = game->getPlayers().value(userGamesIterator.value().second); - if (!player) - continue; - - player->disconnectClient(); - } - roomsLock.unlock(); - - delete user; - - Event_UserLeft event; - event.set_name(userName.toStdString()); - - SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); - clientsLock.lockForRead(); - for (int i = 0; i < clients.size(); ++i) - if (clients[i]->getAcceptsUserListChanges()) - clients[i]->sendProtocolItem(*se); - clientsLock.unlock(); - delete se; + // This function is always called from the main thread via signal/slot. + + clientsLock.lockForWrite(); + Server_AbstractUserInterface *user = externalUsers.take(userName); + externalUsersBySessionId.remove(user->getUserInfo()->session_id()); + clientsLock.unlock(); + + QMap > userGames(user->getGames()); + QMapIterator > userGamesIterator(userGames); + roomsLock.lockForRead(); + while (userGamesIterator.hasNext()) { + userGamesIterator.next(); + Server_Room *room = rooms.value(userGamesIterator.value().first); + if (!room) + continue; + + QReadLocker roomGamesLocker(&room->gamesLock); + Server_Game *game = room->getGames().value(userGamesIterator.key()); + if (!game) + continue; + + QMutexLocker gameLocker(&game->gameMutex); + Server_Player *player = game->getPlayers().value(userGamesIterator.value().second); + if (!player) + continue; + + player->disconnectClient(); + } + roomsLock.unlock(); + + delete user; + + Event_UserLeft event; + event.set_name(userName.toStdString()); + + SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); + clientsLock.lockForRead(); + for (int i = 0; i < clients.size(); ++i) + if (clients[i]->getAcceptsUserListChanges()) + clients[i]->sendProtocolItem(*se); + clientsLock.unlock(); + delete se; } void Server::externalRoomUserJoined(int roomId, const ServerInfo_User &userInfo) { - // This function is always called from the main thread via signal/slot. - QReadLocker locker(&roomsLock); - - Server_Room *room = rooms.value(roomId); - if (!room) { - qDebug() << "externalRoomUserJoined: room id=" << roomId << "not found"; - return; - } - room->addExternalUser(userInfo); + // This function is always called from the main thread via signal/slot. + QReadLocker locker(&roomsLock); + + Server_Room *room = rooms.value(roomId); + if (!room) { + qDebug() << "externalRoomUserJoined: room id=" << roomId << "not found"; + return; + } + room->addExternalUser(userInfo); } void Server::externalRoomUserLeft(int roomId, const QString &userName) { - // This function is always called from the main thread via signal/slot. - QReadLocker locker(&roomsLock); - - Server_Room *room = rooms.value(roomId); - if (!room) { - qDebug() << "externalRoomUserLeft: room id=" << roomId << "not found"; - return; - } - room->removeExternalUser(userName); + // This function is always called from the main thread via signal/slot. + QReadLocker locker(&roomsLock); + + Server_Room *room = rooms.value(roomId); + if (!room) { + qDebug() << "externalRoomUserLeft: room id=" << roomId << "not found"; + return; + } + room->removeExternalUser(userName); } void Server::externalRoomSay(int roomId, const QString &userName, const QString &message) { - // This function is always called from the main thread via signal/slot. - QReadLocker locker(&roomsLock); - - Server_Room *room = rooms.value(roomId); - if (!room) { - qDebug() << "externalRoomSay: room id=" << roomId << "not found"; - return; - } - room->say(userName, message, false); + // This function is always called from the main thread via signal/slot. + QReadLocker locker(&roomsLock); + + Server_Room *room = rooms.value(roomId); + if (!room) { + qDebug() << "externalRoomSay: room id=" << roomId << "not found"; + return; + } + room->say(userName, message, false); } void Server::externalRoomGameListChanged(int roomId, const ServerInfo_Game &gameInfo) { - // This function is always called from the main thread via signal/slot. - QReadLocker locker(&roomsLock); - - Server_Room *room = rooms.value(roomId); - if (!room) { - qDebug() << "externalRoomGameListChanged: room id=" << roomId << "not found"; - return; - } - room->updateExternalGameList(gameInfo); + // This function is always called from the main thread via signal/slot. + QReadLocker locker(&roomsLock); + + Server_Room *room = rooms.value(roomId); + if (!room) { + qDebug() << "externalRoomGameListChanged: room id=" << roomId << "not found"; + return; + } + room->updateExternalGameList(gameInfo); } void Server::externalJoinGameCommandReceived(const Command_JoinGame &cmd, int cmdId, int roomId, int serverId, qint64 sessionId) { - // This function is always called from the main thread via signal/slot. - - try { - QReadLocker roomsLocker(&roomsLock); - QReadLocker clientsLocker(&clientsLock); - - Server_Room *room = rooms.value(roomId); - if (!room) { - qDebug() << "externalJoinGameCommandReceived: room id=" << roomId << "not found"; - throw Response::RespNotInRoom; - } - Server_AbstractUserInterface *userInterface = externalUsersBySessionId.value(sessionId); - if (!userInterface) { - qDebug() << "externalJoinGameCommandReceived: session id=" << sessionId << "not found"; - throw Response::RespNotInRoom; - } - - ResponseContainer responseContainer(cmdId); - Response::ResponseCode responseCode = room->processJoinGameCommand(cmd, responseContainer, userInterface); - userInterface->sendResponseContainer(responseContainer, responseCode); - } catch (Response::ResponseCode code) { - Response response; - response.set_cmd_id(cmdId); - response.set_response_code(code); - - sendIsl_Response(response, serverId, sessionId); - } + // This function is always called from the main thread via signal/slot. + + try { + QReadLocker roomsLocker(&roomsLock); + QReadLocker clientsLocker(&clientsLock); + + Server_Room *room = rooms.value(roomId); + if (!room) { + qDebug() << "externalJoinGameCommandReceived: room id=" << roomId << "not found"; + throw Response::RespNotInRoom; + } + Server_AbstractUserInterface *userInterface = externalUsersBySessionId.value(sessionId); + if (!userInterface) { + qDebug() << "externalJoinGameCommandReceived: session id=" << sessionId << "not found"; + throw Response::RespNotInRoom; + } + + ResponseContainer responseContainer(cmdId); + Response::ResponseCode responseCode = room->processJoinGameCommand(cmd, responseContainer, userInterface); + userInterface->sendResponseContainer(responseContainer, responseCode); + } catch (Response::ResponseCode code) { + Response response; + response.set_cmd_id(cmdId); + response.set_response_code(code); + + sendIsl_Response(response, serverId, sessionId); + } } void Server::externalGameCommandContainerReceived(const CommandContainer &cont, int playerId, int serverId, qint64 sessionId) { - // This function is always called from the main thread via signal/slot. - - try { - ResponseContainer responseContainer(cont.cmd_id()); - Response::ResponseCode finalResponseCode = Response::RespOk; - - QReadLocker roomsLocker(&roomsLock); - Server_Room *room = rooms.value(cont.room_id()); - if (!room) { - qDebug() << "externalGameCommandContainerReceived: room id=" << cont.room_id() << "not found"; - throw Response::RespNotInRoom; - } - - QReadLocker roomGamesLocker(&room->gamesLock); - Server_Game *game = room->getGames().value(cont.game_id()); - if (!game) { - qDebug() << "externalGameCommandContainerReceived: game id=" << cont.game_id() << "not found"; - throw Response::RespNotInRoom; - } - - QMutexLocker gameLocker(&game->gameMutex); - Server_Player *player = game->getPlayers().value(playerId); - if (!player) { - qDebug() << "externalGameCommandContainerReceived: player id=" << playerId << "not found"; - throw Response::RespNotInRoom; - } - - GameEventStorage ges; - for (int i = cont.game_command_size() - 1; i >= 0; --i) { - const GameCommand &sc = cont.game_command(i); - qDebug() << "[ISL]" << QString::fromStdString(sc.ShortDebugString()); - - Response::ResponseCode resp = player->processGameCommand(sc, responseContainer, ges); - - if (resp != Response::RespOk) - finalResponseCode = resp; - } - ges.sendToGame(game); - - if (finalResponseCode != Response::RespNothing) { - player->playerMutex.lock(); - player->getUserInterface()->sendResponseContainer(responseContainer, finalResponseCode); - player->playerMutex.unlock(); - } - } catch (Response::ResponseCode code) { - Response response; - response.set_cmd_id(cont.cmd_id()); - response.set_response_code(code); - - sendIsl_Response(response, serverId, sessionId); - } + // This function is always called from the main thread via signal/slot. + + try { + ResponseContainer responseContainer(cont.cmd_id()); + Response::ResponseCode finalResponseCode = Response::RespOk; + + QReadLocker roomsLocker(&roomsLock); + Server_Room *room = rooms.value(cont.room_id()); + if (!room) { + qDebug() << "externalGameCommandContainerReceived: room id=" << cont.room_id() << "not found"; + throw Response::RespNotInRoom; + } + + QReadLocker roomGamesLocker(&room->gamesLock); + Server_Game *game = room->getGames().value(cont.game_id()); + if (!game) { + qDebug() << "externalGameCommandContainerReceived: game id=" << cont.game_id() << "not found"; + throw Response::RespNotInRoom; + } + + QMutexLocker gameLocker(&game->gameMutex); + Server_Player *player = game->getPlayers().value(playerId); + if (!player) { + qDebug() << "externalGameCommandContainerReceived: player id=" << playerId << "not found"; + throw Response::RespNotInRoom; + } + + GameEventStorage ges; + for (int i = cont.game_command_size() - 1; i >= 0; --i) { + const GameCommand &sc = cont.game_command(i); + qDebug() << "[ISL]" << QString::fromStdString(sc.ShortDebugString()); + + Response::ResponseCode resp = player->processGameCommand(sc, responseContainer, ges); + + if (resp != Response::RespOk) + finalResponseCode = resp; + } + ges.sendToGame(game); + + if (finalResponseCode != Response::RespNothing) { + player->playerMutex.lock(); + player->getUserInterface()->sendResponseContainer(responseContainer, finalResponseCode); + player->playerMutex.unlock(); + } + } catch (Response::ResponseCode code) { + Response response; + response.set_cmd_id(cont.cmd_id()); + response.set_response_code(code); + + sendIsl_Response(response, serverId, sessionId); + } } void Server::externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId) { - // This function is always called from the main thread via signal/slot. - - QReadLocker usersLocker(&clientsLock); - - Server_ProtocolHandler *client = usersBySessionId.value(sessionId); - if (!client) { - qDebug() << "externalGameEventContainerReceived: session" << sessionId << "not found"; - return; - } - client->sendProtocolItem(cont); + // This function is always called from the main thread via signal/slot. + + QReadLocker usersLocker(&clientsLock); + + Server_ProtocolHandler *client = usersBySessionId.value(sessionId); + if (!client) { + qDebug() << "externalGameEventContainerReceived: session" << sessionId << "not found"; + return; + } + client->sendProtocolItem(cont); } void Server::externalResponseReceived(const Response &resp, qint64 sessionId) { - // This function is always called from the main thread via signal/slot. - - QReadLocker usersLocker(&clientsLock); - - Server_ProtocolHandler *client = usersBySessionId.value(sessionId); - if (!client) { - qDebug() << "externalResponseReceived: session" << sessionId << "not found"; - return; - } - client->sendProtocolItem(resp); + // This function is always called from the main thread via signal/slot. + + QReadLocker usersLocker(&clientsLock); + + Server_ProtocolHandler *client = usersBySessionId.value(sessionId); + if (!client) { + qDebug() << "externalResponseReceived: session" << sessionId << "not found"; + return; + } + client->sendProtocolItem(resp); } void Server::broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl) { - // This function is always called from the main thread via signal/slot. - - Event_ListRooms event; - event.add_room_list()->CopyFrom(roomInfo); - - SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); + // This function is always called from the main thread via signal/slot. + + Event_ListRooms event; + event.add_room_list()->CopyFrom(roomInfo); + + SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); - clientsLock.lockForRead(); - for (int i = 0; i < clients.size(); ++i) - if (clients[i]->getAcceptsRoomListChanges()) - clients[i]->sendProtocolItem(*se); - clientsLock.unlock(); - - if (sendToIsl) - sendIsl_SessionEvent(*se); - - delete se; + clientsLock.lockForRead(); + for (int i = 0; i < clients.size(); ++i) + if (clients[i]->getAcceptsRoomListChanges()) + clients[i]->sendProtocolItem(*se); + clientsLock.unlock(); + + if (sendToIsl) + sendIsl_SessionEvent(*se); + + delete se; } void Server::addRoom(Server_Room *newRoom) { - QWriteLocker locker(&roomsLock); - qDebug() << "Adding room: ID=" << newRoom->getId() << "name=" << newRoom->getName(); - rooms.insert(newRoom->getId(), newRoom); - connect(newRoom, SIGNAL(roomInfoChanged(ServerInfo_Room)), this, SLOT(broadcastRoomUpdate(const ServerInfo_Room &)), Qt::QueuedConnection); + QWriteLocker locker(&roomsLock); + qDebug() << "Adding room: ID=" << newRoom->getId() << "name=" << newRoom->getName(); + rooms.insert(newRoom->getId(), newRoom); + connect(newRoom, SIGNAL(roomInfoChanged(ServerInfo_Room)), this, SLOT(broadcastRoomUpdate(const ServerInfo_Room &)), Qt::QueuedConnection); } int Server::getUsersCount() const { - QReadLocker locker(&clientsLock); - return users.size(); + QReadLocker locker(&clientsLock); + return users.size(); } int Server::getGamesCount() const { - int result = 0; - QReadLocker locker(&roomsLock); - QMapIterator roomIterator(rooms); - while (roomIterator.hasNext()) { - Server_Room *room = roomIterator.next().value(); - QReadLocker roomLocker(&room->gamesLock); - result += room->getGames().size(); - } - return result; + int result = 0; + QReadLocker locker(&roomsLock); + QMapIterator roomIterator(rooms); + while (roomIterator.hasNext()) { + Server_Room *room = roomIterator.next().value(); + QReadLocker roomLocker(&room->gamesLock); + result += room->getGames().size(); + } + return result; } void Server::sendIsl_Response(const Response &item, int serverId, qint64 sessionId) { - IslMessage msg; - msg.set_message_type(IslMessage::RESPONSE); - if (sessionId != -1) - msg.set_session_id(sessionId); - msg.mutable_response()->CopyFrom(item); - - emit sigSendIslMessage(msg, serverId); + IslMessage msg; + msg.set_message_type(IslMessage::RESPONSE); + if (sessionId != -1) + msg.set_session_id(sessionId); + msg.mutable_response()->CopyFrom(item); + + emit sigSendIslMessage(msg, serverId); } void Server::sendIsl_SessionEvent(const SessionEvent &item, int serverId, qint64 sessionId) { - IslMessage msg; - msg.set_message_type(IslMessage::SESSION_EVENT); - if (sessionId != -1) - msg.set_session_id(sessionId); - msg.mutable_session_event()->CopyFrom(item); - - emit sigSendIslMessage(msg, serverId); + IslMessage msg; + msg.set_message_type(IslMessage::SESSION_EVENT); + if (sessionId != -1) + msg.set_session_id(sessionId); + msg.mutable_session_event()->CopyFrom(item); + + emit sigSendIslMessage(msg, serverId); } void Server::sendIsl_GameEventContainer(const GameEventContainer &item, int serverId, qint64 sessionId) { - IslMessage msg; - msg.set_message_type(IslMessage::GAME_EVENT_CONTAINER); - if (sessionId != -1) - msg.set_session_id(sessionId); - msg.mutable_game_event_container()->CopyFrom(item); - - emit sigSendIslMessage(msg, serverId); + IslMessage msg; + msg.set_message_type(IslMessage::GAME_EVENT_CONTAINER); + if (sessionId != -1) + msg.set_session_id(sessionId); + msg.mutable_game_event_container()->CopyFrom(item); + + emit sigSendIslMessage(msg, serverId); } void Server::sendIsl_RoomEvent(const RoomEvent &item, int serverId, qint64 sessionId) { - IslMessage msg; - msg.set_message_type(IslMessage::ROOM_EVENT); - if (sessionId != -1) - msg.set_session_id(sessionId); - msg.mutable_room_event()->CopyFrom(item); - - emit sigSendIslMessage(msg, serverId); + IslMessage msg; + msg.set_message_type(IslMessage::ROOM_EVENT); + if (sessionId != -1) + msg.set_session_id(sessionId); + msg.mutable_room_event()->CopyFrom(item); + + emit sigSendIslMessage(msg, serverId); } void Server::sendIsl_GameCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId, int playerId) { - IslMessage msg; - msg.set_message_type(IslMessage::GAME_COMMAND_CONTAINER); - msg.set_session_id(sessionId); - msg.set_player_id(playerId); - - CommandContainer *cont = msg.mutable_game_command(); - cont->CopyFrom(item); - cont->set_room_id(roomId); - - emit sigSendIslMessage(msg, serverId); + IslMessage msg; + msg.set_message_type(IslMessage::GAME_COMMAND_CONTAINER); + msg.set_session_id(sessionId); + msg.set_player_id(playerId); + + CommandContainer *cont = msg.mutable_game_command(); + cont->CopyFrom(item); + cont->set_room_id(roomId); + + emit sigSendIslMessage(msg, serverId); } void Server::sendIsl_RoomCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId) { - IslMessage msg; - msg.set_message_type(IslMessage::ROOM_COMMAND_CONTAINER); - msg.set_session_id(sessionId); - - CommandContainer *cont = msg.mutable_room_command(); - cont->CopyFrom(item); - cont->set_room_id(roomId); - - emit sigSendIslMessage(msg, serverId); + IslMessage msg; + msg.set_message_type(IslMessage::ROOM_COMMAND_CONTAINER); + msg.set_session_id(sessionId); + + CommandContainer *cont = msg.mutable_room_command(); + cont->CopyFrom(item); + cont->set_room_id(roomId); + + emit sigSendIslMessage(msg, serverId); } diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 8792cbb7..2ca3902a 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -21,17 +21,17 @@ #include Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, QObject *parent) - : QObject(parent), - Server_AbstractUserInterface(_server), - deleted(false), - databaseInterface(_databaseInterface), - authState(NotLoggedIn), - acceptsUserListChanges(false), - acceptsRoomListChanges(false), - timeRunning(0), - lastDataReceived(0) + : QObject(parent), + Server_AbstractUserInterface(_server), + deleted(false), + databaseInterface(_databaseInterface), + authState(NotLoggedIn), + acceptsUserListChanges(false), + acceptsRoomListChanges(false), + timeRunning(0), + lastDataReceived(0) { - connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout())); + connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout())); } Server_ProtocolHandler::~Server_ProtocolHandler() @@ -42,541 +42,541 @@ Server_ProtocolHandler::~Server_ProtocolHandler() // The thread must not hold any server locks when calling this (e.g. clientsLock, roomsLock). 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; - r->gamesLock.lockForRead(); - Server_Game *g = r->getGames().value(gameIterator.key()); - if (!g) { - r->gamesLock.unlock(); - continue; - } - g->gameMutex.lock(); - Server_Player *p = g->getPlayers().value(gameIterator.value().second); - if (!p) { - g->gameMutex.unlock(); - r->gamesLock.unlock(); - continue; - } - - p->disconnectClient(); - - g->gameMutex.unlock(); - r->gamesLock.unlock(); - } - server->roomsLock.unlock(); - - server->removeClient(this); - - deleteLater(); + 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; + r->gamesLock.lockForRead(); + Server_Game *g = r->getGames().value(gameIterator.key()); + if (!g) { + r->gamesLock.unlock(); + continue; + } + g->gameMutex.lock(); + Server_Player *p = g->getPlayers().value(gameIterator.value().second); + if (!p) { + g->gameMutex.unlock(); + r->gamesLock.unlock(); + continue; + } + + p->disconnectClient(); + + g->gameMutex.unlock(); + r->gamesLock.unlock(); + } + server->roomsLock.unlock(); + + server->removeClient(this); + + deleteLater(); } void Server_ProtocolHandler::sendProtocolItem(const Response &item) { - ServerMessage msg; - msg.mutable_response()->CopyFrom(item); - msg.set_message_type(ServerMessage::RESPONSE); - - transmitProtocolItem(msg); + ServerMessage msg; + msg.mutable_response()->CopyFrom(item); + msg.set_message_type(ServerMessage::RESPONSE); + + transmitProtocolItem(msg); } void Server_ProtocolHandler::sendProtocolItem(const SessionEvent &item) { - ServerMessage msg; - msg.mutable_session_event()->CopyFrom(item); - msg.set_message_type(ServerMessage::SESSION_EVENT); - - transmitProtocolItem(msg); + ServerMessage msg; + msg.mutable_session_event()->CopyFrom(item); + msg.set_message_type(ServerMessage::SESSION_EVENT); + + transmitProtocolItem(msg); } 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); + ServerMessage msg; + msg.mutable_game_event_container()->CopyFrom(item); + msg.set_message_type(ServerMessage::GAME_EVENT_CONTAINER); + + transmitProtocolItem(msg); } void Server_ProtocolHandler::sendProtocolItem(const RoomEvent &item) { - ServerMessage msg; - msg.mutable_room_event()->CopyFrom(item); - msg.set_message_type(ServerMessage::ROOM_EVENT); - - transmitProtocolItem(msg); + ServerMessage msg; + msg.mutable_room_event()->CopyFrom(item); + msg.set_message_type(ServerMessage::ROOM_EVENT); + + transmitProtocolItem(msg); } Response::ResponseCode Server_ProtocolHandler::processSessionCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { - Response::ResponseCode finalResponseCode = Response::RespOk; - for (int i = cont.session_command_size() - 1; i >= 0; --i) { - Response::ResponseCode resp = Response::RespInvalidCommand; - const SessionCommand &sc = cont.session_command(i); - const int num = getPbExtension(sc); - if (num != SessionCommand::PING) { // don't log ping commands - if (num == SessionCommand::LOGIN) { // log login commands, but hide passwords - SessionCommand debugSc(sc); - debugSc.MutableExtension(Command_Login::ext)->clear_password(); - logDebugMessage(QString::fromStdString(debugSc.ShortDebugString())); - } else - logDebugMessage(QString::fromStdString(sc.ShortDebugString())); - } - switch ((SessionCommand::SessionCommandType) num) { - case SessionCommand::PING: resp = cmdPing(sc.GetExtension(Command_Ping::ext), rc); break; - case SessionCommand::LOGIN: resp = cmdLogin(sc.GetExtension(Command_Login::ext), rc); break; - case SessionCommand::MESSAGE: resp = cmdMessage(sc.GetExtension(Command_Message::ext), rc); break; - case SessionCommand::GET_GAMES_OF_USER: resp = cmdGetGamesOfUser(sc.GetExtension(Command_GetGamesOfUser::ext), rc); break; - case SessionCommand::GET_USER_INFO: resp = cmdGetUserInfo(sc.GetExtension(Command_GetUserInfo::ext), rc); break; - case SessionCommand::LIST_ROOMS: resp = cmdListRooms(sc.GetExtension(Command_ListRooms::ext), rc); break; - case SessionCommand::JOIN_ROOM: resp = cmdJoinRoom(sc.GetExtension(Command_JoinRoom::ext), rc); break; - case SessionCommand::LIST_USERS: resp = cmdListUsers(sc.GetExtension(Command_ListUsers::ext), rc); break; - default: resp = processExtendedSessionCommand(num, sc, rc); - } - if (resp != Response::RespOk) - finalResponseCode = resp; - } - return finalResponseCode; + Response::ResponseCode finalResponseCode = Response::RespOk; + for (int i = cont.session_command_size() - 1; i >= 0; --i) { + Response::ResponseCode resp = Response::RespInvalidCommand; + const SessionCommand &sc = cont.session_command(i); + const int num = getPbExtension(sc); + if (num != SessionCommand::PING) { // don't log ping commands + if (num == SessionCommand::LOGIN) { // log login commands, but hide passwords + SessionCommand debugSc(sc); + debugSc.MutableExtension(Command_Login::ext)->clear_password(); + logDebugMessage(QString::fromStdString(debugSc.ShortDebugString())); + } else + logDebugMessage(QString::fromStdString(sc.ShortDebugString())); + } + switch ((SessionCommand::SessionCommandType) num) { + case SessionCommand::PING: resp = cmdPing(sc.GetExtension(Command_Ping::ext), rc); break; + case SessionCommand::LOGIN: resp = cmdLogin(sc.GetExtension(Command_Login::ext), rc); break; + case SessionCommand::MESSAGE: resp = cmdMessage(sc.GetExtension(Command_Message::ext), rc); break; + case SessionCommand::GET_GAMES_OF_USER: resp = cmdGetGamesOfUser(sc.GetExtension(Command_GetGamesOfUser::ext), rc); break; + case SessionCommand::GET_USER_INFO: resp = cmdGetUserInfo(sc.GetExtension(Command_GetUserInfo::ext), rc); break; + case SessionCommand::LIST_ROOMS: resp = cmdListRooms(sc.GetExtension(Command_ListRooms::ext), rc); break; + case SessionCommand::JOIN_ROOM: resp = cmdJoinRoom(sc.GetExtension(Command_JoinRoom::ext), rc); break; + case SessionCommand::LIST_USERS: resp = cmdListUsers(sc.GetExtension(Command_ListUsers::ext), rc); break; + default: resp = processExtendedSessionCommand(num, sc, rc); + } + if (resp != Response::RespOk) + finalResponseCode = resp; + } + return finalResponseCode; } Response::ResponseCode Server_ProtocolHandler::processRoomCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { - if (authState == NotLoggedIn) - return Response::RespLoginNeeded; + if (authState == NotLoggedIn) + return Response::RespLoginNeeded; - QReadLocker locker(&server->roomsLock); - 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; - const RoomCommand &sc = cont.room_command(i); - const int num = getPbExtension(sc); - logDebugMessage(QString::fromStdString(sc.ShortDebugString())); - switch ((RoomCommand::RoomCommandType) num) { - case RoomCommand::LEAVE_ROOM: resp = cmdLeaveRoom(sc.GetExtension(Command_LeaveRoom::ext), room, rc); break; - case RoomCommand::ROOM_SAY: resp = cmdRoomSay(sc.GetExtension(Command_RoomSay::ext), room, rc); break; - case RoomCommand::CREATE_GAME: resp = cmdCreateGame(sc.GetExtension(Command_CreateGame::ext), room, rc); break; - case RoomCommand::JOIN_GAME: resp = cmdJoinGame(sc.GetExtension(Command_JoinGame::ext), room, rc); break; - } - if (resp != Response::RespOk) - finalResponseCode = resp; - } - return finalResponseCode; + QReadLocker locker(&server->roomsLock); + 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; + const RoomCommand &sc = cont.room_command(i); + const int num = getPbExtension(sc); + logDebugMessage(QString::fromStdString(sc.ShortDebugString())); + switch ((RoomCommand::RoomCommandType) num) { + case RoomCommand::LEAVE_ROOM: resp = cmdLeaveRoom(sc.GetExtension(Command_LeaveRoom::ext), room, rc); break; + case RoomCommand::ROOM_SAY: resp = cmdRoomSay(sc.GetExtension(Command_RoomSay::ext), room, rc); break; + case RoomCommand::CREATE_GAME: resp = cmdCreateGame(sc.GetExtension(Command_CreateGame::ext), room, rc); break; + case RoomCommand::JOIN_GAME: resp = cmdJoinGame(sc.GetExtension(Command_JoinGame::ext), room, rc); break; + } + if (resp != Response::RespOk) + finalResponseCode = resp; + } + return finalResponseCode; } Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { - 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) { - if (room->getExternalGames().contains(cont.game_id())) { - server->sendIsl_GameCommand(cont, - room->getExternalGames().value(cont.game_id()).server_id(), - userInfo->session_id(), - roomIdAndPlayerId.first, - roomIdAndPlayerId.second - ); - return Response::RespNothing; - } - return Response::RespNotInRoom; - } - - QMutexLocker gameLocker(&game->gameMutex); - Server_Player *player = game->getPlayers().value(roomIdAndPlayerId.second); - if (!player) - return Response::RespNotInRoom; - - GameEventStorage ges; - Response::ResponseCode finalResponseCode = Response::RespOk; - for (int i = cont.game_command_size() - 1; i >= 0; --i) { - const GameCommand &sc = cont.game_command(i); - logDebugMessage(QString("game %1 player %2: ").arg(cont.game_id()).arg(roomIdAndPlayerId.second) + QString::fromStdString(sc.ShortDebugString())); - - Response::ResponseCode resp = player->processGameCommand(sc, rc, ges); + 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) { + if (room->getExternalGames().contains(cont.game_id())) { + server->sendIsl_GameCommand(cont, + room->getExternalGames().value(cont.game_id()).server_id(), + userInfo->session_id(), + roomIdAndPlayerId.first, + roomIdAndPlayerId.second + ); + return Response::RespNothing; + } + return Response::RespNotInRoom; + } + + QMutexLocker gameLocker(&game->gameMutex); + Server_Player *player = game->getPlayers().value(roomIdAndPlayerId.second); + if (!player) + return Response::RespNotInRoom; + + GameEventStorage ges; + Response::ResponseCode finalResponseCode = Response::RespOk; + for (int i = cont.game_command_size() - 1; i >= 0; --i) { + const GameCommand &sc = cont.game_command(i); + logDebugMessage(QString("game %1 player %2: ").arg(cont.game_id()).arg(roomIdAndPlayerId.second) + QString::fromStdString(sc.ShortDebugString())); + + Response::ResponseCode resp = player->processGameCommand(sc, rc, ges); - if (resp != Response::RespOk) - finalResponseCode = resp; - } - ges.sendToGame(game); - - return finalResponseCode; + if (resp != Response::RespOk) + finalResponseCode = resp; + } + ges.sendToGame(game); + + return finalResponseCode; } Response::ResponseCode Server_ProtocolHandler::processModeratorCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { - if (!userInfo) - return Response::RespLoginNeeded; - if (!(userInfo->user_level() & ServerInfo_User::IsModerator)) - return Response::RespLoginNeeded; + if (!userInfo) + return Response::RespLoginNeeded; + if (!(userInfo->user_level() & ServerInfo_User::IsModerator)) + return Response::RespLoginNeeded; - Response::ResponseCode finalResponseCode = Response::RespOk; - for (int i = cont.moderator_command_size() - 1; i >= 0; --i) { - Response::ResponseCode resp = Response::RespInvalidCommand; - 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; - } - return finalResponseCode; + Response::ResponseCode finalResponseCode = Response::RespOk; + for (int i = cont.moderator_command_size() - 1; i >= 0; --i) { + Response::ResponseCode resp = Response::RespInvalidCommand; + 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; + } + return finalResponseCode; } Response::ResponseCode Server_ProtocolHandler::processAdminCommandContainer(const CommandContainer &cont, ResponseContainer &rc) { - if (!userInfo) - return Response::RespLoginNeeded; - if (!(userInfo->user_level() & ServerInfo_User::IsAdmin)) - return Response::RespLoginNeeded; + if (!userInfo) + return Response::RespLoginNeeded; + if (!(userInfo->user_level() & ServerInfo_User::IsAdmin)) + return Response::RespLoginNeeded; - Response::ResponseCode finalResponseCode = Response::RespOk; - for (int i = cont.admin_command_size() - 1; i >= 0; --i) { - Response::ResponseCode resp = Response::RespInvalidCommand; - 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; - } - return finalResponseCode; + Response::ResponseCode finalResponseCode = Response::RespOk; + for (int i = cont.admin_command_size() - 1; i >= 0; --i) { + Response::ResponseCode resp = Response::RespInvalidCommand; + 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; + } + return finalResponseCode; } void Server_ProtocolHandler::processCommandContainer(const CommandContainer &cont) { - // 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()) - finalResponseCode = processRoomCommandContainer(cont, responseContainer); - else if (cont.session_command_size()) - finalResponseCode = processSessionCommandContainer(cont, responseContainer); - else if (cont.moderator_command_size()) - finalResponseCode = processModeratorCommandContainer(cont, responseContainer); - else if (cont.admin_command_size()) - finalResponseCode = processAdminCommandContainer(cont, responseContainer); - else - finalResponseCode = Response::RespInvalidCommand; - - if ((finalResponseCode != Response::RespNothing)) - sendResponseContainer(responseContainer, finalResponseCode); + // 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()) + finalResponseCode = processRoomCommandContainer(cont, responseContainer); + else if (cont.session_command_size()) + finalResponseCode = processSessionCommandContainer(cont, responseContainer); + else if (cont.moderator_command_size()) + finalResponseCode = processModeratorCommandContainer(cont, responseContainer); + else if (cont.admin_command_size()) + finalResponseCode = processAdminCommandContainer(cont, responseContainer); + else + finalResponseCode = Response::RespInvalidCommand; + + if ((finalResponseCode != Response::RespNothing)) + sendResponseContainer(responseContainer, finalResponseCode); } void Server_ProtocolHandler::pingClockTimeout() { - 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 (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime()) - prepareDestroy(); - ++timeRunning; + 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 (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime()) + prepareDestroy(); + ++timeRunning; } Response::ResponseCode Server_ProtocolHandler::cmdPing(const Command_Ping & /*cmd*/, ResponseContainer & /*rc*/) { - return Response::RespOk; + return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd, ResponseContainer &rc) { - QString userName = QString::fromStdString(cmd.user_name()).simplified(); - if (userName.isEmpty() || (userInfo != 0)) - return Response::RespContextError; - QString reasonStr; - int banSecondsLeft = 0; - AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft); - switch (res) { - case UserIsBanned: { - Response_Login *re = new Response_Login; - re->set_denied_reason_str(reasonStr.toStdString()); - if (banSecondsLeft != 0) - re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsLeft).toTime_t()); - rc.setResponseExtension(re); - return Response::RespUserIsBanned; - } - case NotLoggedIn: return Response::RespWrongPassword; - case WouldOverwriteOldSession: return Response::RespWouldOverwriteOldSession; - case UsernameInvalid: return Response::RespUsernameInvalid; - case RegistrationRequired: return Response::RespRegistrationRequired; - 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; + QString userName = QString::fromStdString(cmd.user_name()).simplified(); + if (userName.isEmpty() || (userInfo != 0)) + return Response::RespContextError; + QString reasonStr; + int banSecondsLeft = 0; + AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft); + switch (res) { + case UserIsBanned: { + Response_Login *re = new Response_Login; + re->set_denied_reason_str(reasonStr.toStdString()); + if (banSecondsLeft != 0) + re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsLeft).toTime_t()); + rc.setResponseExtension(re); + return Response::RespUserIsBanned; + } + case NotLoggedIn: return Response::RespWrongPassword; + case WouldOverwriteOldSession: return Response::RespWouldOverwriteOldSession; + case UsernameInvalid: return Response::RespUsernameInvalid; + case RegistrationRequired: return Response::RespRegistrationRequired; + 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; } Response::ResponseCode Server_ProtocolHandler::cmdMessage(const Command_Message &cmd, ResponseContainer &rc) { - 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); - - return Response::RespOk; + 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); + + return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdGetGamesOfUser(const Command_GetGamesOfUser &cmd, ResponseContainer &rc) { - 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()); - while (roomIterator.hasNext()) { - Server_Room *room = roomIterator.next().value(); - room->gamesLock.lockForRead(); - room->getInfo(*re->add_room_list(), false, true); - QListIterator gameIterator(room->getGamesOfUser(QString::fromStdString(cmd.user_name()))); - while (gameIterator.hasNext()) - re->add_game_list()->CopyFrom(gameIterator.next()); - room->gamesLock.unlock(); - } - server->roomsLock.unlock(); - - rc.setResponseExtension(re); - return Response::RespOk; + 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()); + while (roomIterator.hasNext()) { + Server_Room *room = roomIterator.next().value(); + room->gamesLock.lockForRead(); + room->getInfo(*re->add_room_list(), false, true); + QListIterator gameIterator(room->getGamesOfUser(QString::fromStdString(cmd.user_name()))); + while (gameIterator.hasNext()) + re->add_game_list()->CopyFrom(gameIterator.next()); + room->gamesLock.unlock(); + } + server->roomsLock.unlock(); + + rc.setResponseExtension(re); + return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdGetUserInfo(const Command_GetUserInfo &cmd, ResponseContainer &rc) { - 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; + 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; } Response::ResponseCode Server_ProtocolHandler::cmdListRooms(const Command_ListRooms & /*cmd*/, ResponseContainer &rc) { - 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; + 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; } Response::ResponseCode Server_ProtocolHandler::cmdJoinRoom(const Command_JoinRoom &cmd, ResponseContainer &rc) { - 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; + 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; } Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUsers & /*cmd*/, ResponseContainer &rc) { - if (authState == NotLoggedIn) - return Response::RespLoginNeeded; - - Response_ListUsers *re = new Response_ListUsers; - server->clientsLock.lockForRead(); - QMapIterator userIterator = server->getUsers(); - while (userIterator.hasNext()) - re->add_user_list()->CopyFrom(userIterator.next().value()->copyUserInfo(false)); - 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; + if (authState == NotLoggedIn) + return Response::RespLoginNeeded; + + Response_ListUsers *re = new Response_ListUsers; + server->clientsLock.lockForRead(); + QMapIterator userIterator = server->getUsers(); + while (userIterator.hasNext()) + re->add_user_list()->CopyFrom(userIterator.next().value()->copyUserInfo(false)); + 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; } Response::ResponseCode Server_ProtocolHandler::cmdLeaveRoom(const Command_LeaveRoom & /*cmd*/, Server_Room *room, ResponseContainer & /*rc*/) { - rooms.remove(room->getId()); - room->removeClient(this); - return Response::RespOk; + rooms.remove(room->getId()); + room->removeClient(this); + return Response::RespOk; } 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()) - messageSizeOverTime.prepend(0); - 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); - return Response::RespOk; + QString msg = QString::fromStdString(cmd.message()); + + if (server->getMessageCountingInterval() > 0) { + int totalSize = 0, totalCount = 0; + if (messageSizeOverTime.isEmpty()) + messageSizeOverTime.prepend(0); + 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); + return Response::RespOk; } Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room *room, ResponseContainer &rc) { - if (authState == NotLoggedIn) - return Response::RespLoginNeeded; - 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; + if (authState == NotLoggedIn) + return Response::RespLoginNeeded; + 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; } Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGame &cmd, Server_Room *room, ResponseContainer &rc) { - if (authState == NotLoggedIn) - return Response::RespLoginNeeded; - - return room->processJoinGameCommand(cmd, rc, this); + 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 bb83b53c..14926463 100644 --- a/servatrice/servatrice.ini.example +++ b/servatrice/servatrice.ini.example @@ -7,7 +7,6 @@ id=1 number_pools=1 writelog=1 logfilters="" -regonly=0 [servernetwork] active=0 @@ -17,6 +16,7 @@ ssl_key=ssl_key.pem [authentication] method=none +regonly=0 [database] type=none diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index 0b087ccb..4c12975b 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -38,481 +38,481 @@ #include "pb/event_connection_closed.pb.h" Servatrice_GameServer::Servatrice_GameServer(Servatrice *_server, int _numberPools, const QSqlDatabase &_sqlDatabase, QObject *parent) - : QTcpServer(parent), - server(_server) + : QTcpServer(parent), + server(_server) { - if (_numberPools == 0) { - server->setThreaded(false); - Servatrice_DatabaseInterface *newDatabaseInterface = new Servatrice_DatabaseInterface(0, server); - Servatrice_ConnectionPool *newPool = new Servatrice_ConnectionPool(newDatabaseInterface); - - server->addDatabaseInterface(thread(), newDatabaseInterface); - newDatabaseInterface->initDatabase(_sqlDatabase); - - connectionPools.append(newPool); - } else - for (int i = 0; i < _numberPools; ++i) { - Servatrice_DatabaseInterface *newDatabaseInterface = new Servatrice_DatabaseInterface(i, server); - Servatrice_ConnectionPool *newPool = new Servatrice_ConnectionPool(newDatabaseInterface); - - QThread *newThread = new QThread; - newThread->setObjectName("pool_" + QString::number(i)); - newPool->moveToThread(newThread); - newDatabaseInterface->moveToThread(newThread); - server->addDatabaseInterface(newThread, newDatabaseInterface); - - newThread->start(); - QMetaObject::invokeMethod(newDatabaseInterface, "initDatabase", Qt::BlockingQueuedConnection, Q_ARG(QSqlDatabase, _sqlDatabase)); - - connectionPools.append(newPool); - } + if (_numberPools == 0) { + server->setThreaded(false); + Servatrice_DatabaseInterface *newDatabaseInterface = new Servatrice_DatabaseInterface(0, server); + Servatrice_ConnectionPool *newPool = new Servatrice_ConnectionPool(newDatabaseInterface); + + server->addDatabaseInterface(thread(), newDatabaseInterface); + newDatabaseInterface->initDatabase(_sqlDatabase); + + connectionPools.append(newPool); + } else + for (int i = 0; i < _numberPools; ++i) { + Servatrice_DatabaseInterface *newDatabaseInterface = new Servatrice_DatabaseInterface(i, server); + Servatrice_ConnectionPool *newPool = new Servatrice_ConnectionPool(newDatabaseInterface); + + QThread *newThread = new QThread; + newThread->setObjectName("pool_" + QString::number(i)); + newPool->moveToThread(newThread); + newDatabaseInterface->moveToThread(newThread); + server->addDatabaseInterface(newThread, newDatabaseInterface); + + newThread->start(); + QMetaObject::invokeMethod(newDatabaseInterface, "initDatabase", Qt::BlockingQueuedConnection, Q_ARG(QSqlDatabase, _sqlDatabase)); + + connectionPools.append(newPool); + } } Servatrice_GameServer::~Servatrice_GameServer() { - for (int i = 0; i < connectionPools.size(); ++i) { - logger->logMessage(QString("Closing pool %1...").arg(i)); - QThread *poolThread = connectionPools[i]->thread(); - connectionPools[i]->deleteLater(); // pool destructor calls thread()->quit() - poolThread->wait(); - } + for (int i = 0; i < connectionPools.size(); ++i) { + logger->logMessage(QString("Closing pool %1...").arg(i)); + QThread *poolThread = connectionPools[i]->thread(); + connectionPools[i]->deleteLater(); // pool destructor calls thread()->quit() + poolThread->wait(); + } } void Servatrice_GameServer::incomingConnection(int socketDescriptor) { - // Determine connection pool with smallest client count - int minClientCount = -1; - int poolIndex = -1; - QStringList debugStr; - for (int i = 0; i < connectionPools.size(); ++i) { - const int clientCount = connectionPools[i]->getClientCount(); - if ((poolIndex == -1) || (clientCount < minClientCount)) { - minClientCount = clientCount; - poolIndex = i; - } - debugStr.append(QString::number(clientCount)); - } - qDebug() << "Pool utilisation:" << debugStr; - Servatrice_ConnectionPool *pool = connectionPools[poolIndex]; - - ServerSocketInterface *ssi = new ServerSocketInterface(server, pool->getDatabaseInterface()); - ssi->moveToThread(pool->thread()); - pool->addClient(); - connect(ssi, SIGNAL(destroyed()), pool, SLOT(removeClient())); - - QMetaObject::invokeMethod(ssi, "initConnection", Qt::QueuedConnection, Q_ARG(int, socketDescriptor)); + // Determine connection pool with smallest client count + int minClientCount = -1; + int poolIndex = -1; + QStringList debugStr; + for (int i = 0; i < connectionPools.size(); ++i) { + const int clientCount = connectionPools[i]->getClientCount(); + if ((poolIndex == -1) || (clientCount < minClientCount)) { + minClientCount = clientCount; + poolIndex = i; + } + debugStr.append(QString::number(clientCount)); + } + qDebug() << "Pool utilisation:" << debugStr; + Servatrice_ConnectionPool *pool = connectionPools[poolIndex]; + + ServerSocketInterface *ssi = new ServerSocketInterface(server, pool->getDatabaseInterface()); + ssi->moveToThread(pool->thread()); + pool->addClient(); + connect(ssi, SIGNAL(destroyed()), pool, SLOT(removeClient())); + + QMetaObject::invokeMethod(ssi, "initConnection", Qt::QueuedConnection, Q_ARG(int, socketDescriptor)); } void Servatrice_IslServer::incomingConnection(int socketDescriptor) { - QThread *thread = new QThread; - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - - IslInterface *interface = new IslInterface(socketDescriptor, cert, privateKey, server); - interface->moveToThread(thread); - connect(interface, SIGNAL(destroyed()), thread, SLOT(quit())); - - thread->start(); - QMetaObject::invokeMethod(interface, "initServer", Qt::QueuedConnection); + QThread *thread = new QThread; + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + IslInterface *interface = new IslInterface(socketDescriptor, cert, privateKey, server); + interface->moveToThread(thread); + connect(interface, SIGNAL(destroyed()), thread, SLOT(quit())); + + thread->start(); + QMetaObject::invokeMethod(interface, "initServer", Qt::QueuedConnection); } Servatrice::Servatrice(QSettings *_settings, QObject *parent) - : Server(true, parent), settings(_settings), uptime(0), shutdownTimer(0) + : Server(true, parent), settings(_settings), uptime(0), shutdownTimer(0) { - qRegisterMetaType("QSqlDatabase"); + qRegisterMetaType("QSqlDatabase"); } Servatrice::~Servatrice() { - gameServer->close(); - prepareDestroy(); + gameServer->close(); + prepareDestroy(); } bool Servatrice::initServer() { - serverName = settings->value("server/name").toString(); - serverId = settings->value("server/id", 0).toInt(); - bool regServerOnly = settings->value("server/regonly", 0).toBool(); - - const QString authenticationMethodStr = settings->value("authentication/method").toString(); - if (authenticationMethodStr == "sql") { - authenticationMethod = AuthenticationSql; - } else { - if (regServerOnly) { - qDebug() << "Registration only server enabled but no DB Connection : Error."; - return false; - } - authenticationMethod = AuthenticationNone; - } - - QString dbTypeStr = settings->value("database/type").toString(); - if (dbTypeStr == "mysql") - databaseType = DatabaseMySql; - else - databaseType = DatabaseNone; - - servatriceDatabaseInterface = new Servatrice_DatabaseInterface(-1, this); - setDatabaseInterface(servatriceDatabaseInterface); - - if (databaseType != DatabaseNone) { - settings->beginGroup("database"); - dbPrefix = settings->value("prefix").toString(); - servatriceDatabaseInterface->initDatabase("QMYSQL", - settings->value("hostname").toString(), - settings->value("database").toString(), - settings->value("user").toString(), - settings->value("password").toString()); - settings->endGroup(); - - updateServerList(); - - qDebug() << "Clearing previous sessions..."; - servatriceDatabaseInterface->clearSessionTables(); - } - - const QString roomMethod = settings->value("rooms/method").toString(); - if (roomMethod == "sql") { - QSqlQuery query(servatriceDatabaseInterface->getDatabase()); - query.prepare("select id, name, descr, auto_join, join_message from " + dbPrefix + "_rooms order by id asc"); - servatriceDatabaseInterface->execSqlQuery(query); - while (query.next()) { - QSqlQuery query2(servatriceDatabaseInterface->getDatabase()); - query2.prepare("select name from " + dbPrefix + "_rooms_gametypes where id_room = :id_room"); - query2.bindValue(":id_room", query.value(0).toInt()); - servatriceDatabaseInterface->execSqlQuery(query2); - QStringList gameTypes; - while (query2.next()) - gameTypes.append(query2.value(0).toString()); - - addRoom(new Server_Room(query.value(0).toInt(), - query.value(1).toString(), - query.value(2).toString(), - query.value(3).toInt(), - query.value(4).toString(), - gameTypes, - this - )); - } - } else { - int size = settings->beginReadArray("rooms/roomlist"); - for (int i = 0; i < size; ++i) { - settings->setArrayIndex(i); - - QStringList gameTypes; - int size2 = settings->beginReadArray("game_types"); - for (int j = 0; j < size2; ++j) { - settings->setArrayIndex(j); - gameTypes.append(settings->value("name").toString()); - } - settings->endArray(); - - Server_Room *newRoom = new Server_Room( - i, - settings->value("name").toString(), - settings->value("description").toString(), - settings->value("autojoin").toBool(), - settings->value("joinmessage").toString(), - gameTypes, - this - ); - addRoom(newRoom); - } - settings->endArray(); - } - - updateLoginMessage(); - - maxGameInactivityTime = settings->value("game/max_game_inactivity_time").toInt(); - maxPlayerInactivityTime = settings->value("game/max_player_inactivity_time").toInt(); - - maxUsersPerAddress = settings->value("security/max_users_per_address").toInt(); - 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(); + serverName = settings->value("server/name").toString(); + serverId = settings->value("server/id", 0).toInt(); + bool regServerOnly = settings->value("server/regonly", 0).toBool(); + + const QString authenticationMethodStr = settings->value("authentication/method").toString(); + if (authenticationMethodStr == "sql") { + authenticationMethod = AuthenticationSql; + } else { + if (regServerOnly) { + qDebug() << "Registration only server enabled but no DB Connection : Error."; + return false; + } + authenticationMethod = AuthenticationNone; + } + + QString dbTypeStr = settings->value("database/type").toString(); + if (dbTypeStr == "mysql") + databaseType = DatabaseMySql; + else + databaseType = DatabaseNone; + + servatriceDatabaseInterface = new Servatrice_DatabaseInterface(-1, this); + setDatabaseInterface(servatriceDatabaseInterface); + + if (databaseType != DatabaseNone) { + settings->beginGroup("database"); + dbPrefix = settings->value("prefix").toString(); + servatriceDatabaseInterface->initDatabase("QMYSQL", + settings->value("hostname").toString(), + settings->value("database").toString(), + settings->value("user").toString(), + settings->value("password").toString()); + settings->endGroup(); + + updateServerList(); + + qDebug() << "Clearing previous sessions..."; + servatriceDatabaseInterface->clearSessionTables(); + } + + const QString roomMethod = settings->value("rooms/method").toString(); + if (roomMethod == "sql") { + QSqlQuery query(servatriceDatabaseInterface->getDatabase()); + query.prepare("select id, name, descr, auto_join, join_message from " + dbPrefix + "_rooms order by id asc"); + servatriceDatabaseInterface->execSqlQuery(query); + while (query.next()) { + QSqlQuery query2(servatriceDatabaseInterface->getDatabase()); + query2.prepare("select name from " + dbPrefix + "_rooms_gametypes where id_room = :id_room"); + query2.bindValue(":id_room", query.value(0).toInt()); + servatriceDatabaseInterface->execSqlQuery(query2); + QStringList gameTypes; + while (query2.next()) + gameTypes.append(query2.value(0).toString()); + + addRoom(new Server_Room(query.value(0).toInt(), + query.value(1).toString(), + query.value(2).toString(), + query.value(3).toInt(), + query.value(4).toString(), + gameTypes, + this + )); + } + } else { + int size = settings->beginReadArray("rooms/roomlist"); + for (int i = 0; i < size; ++i) { + settings->setArrayIndex(i); + + QStringList gameTypes; + int size2 = settings->beginReadArray("game_types"); + for (int j = 0; j < size2; ++j) { + settings->setArrayIndex(j); + gameTypes.append(settings->value("name").toString()); + } + settings->endArray(); + + Server_Room *newRoom = new Server_Room( + i, + settings->value("name").toString(), + settings->value("description").toString(), + settings->value("autojoin").toBool(), + settings->value("joinmessage").toString(), + gameTypes, + this + ); + addRoom(newRoom); + } + settings->endArray(); + } + + updateLoginMessage(); + + maxGameInactivityTime = settings->value("game/max_game_inactivity_time").toInt(); + maxPlayerInactivityTime = settings->value("game/max_player_inactivity_time").toInt(); + + maxUsersPerAddress = settings->value("security/max_users_per_address").toInt(); + 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(); - try { if (settings->value("servernetwork/active", 0).toInt()) { - qDebug() << "Connecting to ISL network."; - const QString certFileName = settings->value("servernetwork/ssl_cert").toString(); - const QString keyFileName = settings->value("servernetwork/ssl_key").toString(); - qDebug() << "Loading certificate..."; - QFile certFile(certFileName); - if (!certFile.open(QIODevice::ReadOnly)) - throw QString("Error opening certificate file: %1").arg(certFileName); - QSslCertificate cert(&certFile); - if (!cert.isValid()) - throw(QString("Invalid certificate.")); - qDebug() << "Loading private key..."; - QFile keyFile(keyFileName); - if (!keyFile.open(QIODevice::ReadOnly)) - throw QString("Error opening private key file: %1").arg(keyFileName); - QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); - if (key.isNull()) - throw QString("Invalid private key."); - - QMutableListIterator serverIterator(serverList); - while (serverIterator.hasNext()) { - const ServerProperties &prop = serverIterator.next(); - if (prop.cert == cert) { - serverIterator.remove(); - continue; - } - - QThread *thread = new QThread; - thread->setObjectName("isl_" + QString::number(prop.id)); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - - IslInterface *interface = new IslInterface(prop.id, prop.hostname, prop.address.toString(), prop.controlPort, prop.cert, cert, key, this); - interface->moveToThread(thread); - connect(interface, SIGNAL(destroyed()), thread, SLOT(quit())); - - thread->start(); - QMetaObject::invokeMethod(interface, "initClient", Qt::BlockingQueuedConnection); - } - - const int networkPort = settings->value("servernetwork/port", 14747).toInt(); - qDebug() << "Starting ISL server on port" << networkPort; - - islServer = new Servatrice_IslServer(this, cert, key, this); - if (islServer->listen(QHostAddress::Any, networkPort)) - qDebug() << "ISL server listening."; - else - throw QString("islServer->listen()"); - } } catch (QString error) { - qDebug() << "ERROR --" << error; - return false; - } - - pingClock = new QTimer(this); - connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout())); - pingClock->start(1000); - - int statusUpdateTime = settings->value("server/statusupdate").toInt(); - statusUpdateClock = new QTimer(this); - connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate())); - if (statusUpdateTime != 0) { - qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms"; - statusUpdateClock->start(statusUpdateTime); - } - - const int numberPools = settings->value("server/number_pools", 1).toInt(); - gameServer = new Servatrice_GameServer(this, numberPools, servatriceDatabaseInterface->getDatabase(), this); - gameServer->setMaxPendingConnections(1000); - const int gamePort = settings->value("server/port", 4747).toInt(); - qDebug() << "Starting server on port" << gamePort; - if (gameServer->listen(QHostAddress::Any, gamePort)) - qDebug() << "Server listening."; - else { - qDebug() << "gameServer->listen(): Error."; - return false; - } - return true; + try { if (settings->value("servernetwork/active", 0).toInt()) { + qDebug() << "Connecting to ISL network."; + const QString certFileName = settings->value("servernetwork/ssl_cert").toString(); + const QString keyFileName = settings->value("servernetwork/ssl_key").toString(); + qDebug() << "Loading certificate..."; + QFile certFile(certFileName); + if (!certFile.open(QIODevice::ReadOnly)) + throw QString("Error opening certificate file: %1").arg(certFileName); + QSslCertificate cert(&certFile); + if (!cert.isValid()) + throw(QString("Invalid certificate.")); + qDebug() << "Loading private key..."; + QFile keyFile(keyFileName); + if (!keyFile.open(QIODevice::ReadOnly)) + throw QString("Error opening private key file: %1").arg(keyFileName); + QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + if (key.isNull()) + throw QString("Invalid private key."); + + QMutableListIterator serverIterator(serverList); + while (serverIterator.hasNext()) { + const ServerProperties &prop = serverIterator.next(); + if (prop.cert == cert) { + serverIterator.remove(); + continue; + } + + QThread *thread = new QThread; + thread->setObjectName("isl_" + QString::number(prop.id)); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + + IslInterface *interface = new IslInterface(prop.id, prop.hostname, prop.address.toString(), prop.controlPort, prop.cert, cert, key, this); + interface->moveToThread(thread); + connect(interface, SIGNAL(destroyed()), thread, SLOT(quit())); + + thread->start(); + QMetaObject::invokeMethod(interface, "initClient", Qt::BlockingQueuedConnection); + } + + const int networkPort = settings->value("servernetwork/port", 14747).toInt(); + qDebug() << "Starting ISL server on port" << networkPort; + + islServer = new Servatrice_IslServer(this, cert, key, this); + if (islServer->listen(QHostAddress::Any, networkPort)) + qDebug() << "ISL server listening."; + else + throw QString("islServer->listen()"); + } } catch (QString error) { + qDebug() << "ERROR --" << error; + return false; + } + + pingClock = new QTimer(this); + connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout())); + pingClock->start(1000); + + int statusUpdateTime = settings->value("server/statusupdate").toInt(); + statusUpdateClock = new QTimer(this); + connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate())); + if (statusUpdateTime != 0) { + qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms"; + statusUpdateClock->start(statusUpdateTime); + } + + const int numberPools = settings->value("server/number_pools", 1).toInt(); + gameServer = new Servatrice_GameServer(this, numberPools, servatriceDatabaseInterface->getDatabase(), this); + gameServer->setMaxPendingConnections(1000); + const int gamePort = settings->value("server/port", 4747).toInt(); + qDebug() << "Starting server on port" << gamePort; + if (gameServer->listen(QHostAddress::Any, gamePort)) + qDebug() << "Server listening."; + else { + qDebug() << "gameServer->listen(): Error."; + return false; + } + return true; } void Servatrice::addDatabaseInterface(QThread *thread, Servatrice_DatabaseInterface *databaseInterface) { - databaseInterfaces.insert(thread, databaseInterface); + databaseInterfaces.insert(thread, databaseInterface); } void Servatrice::updateServerList() { - qDebug() << "Updating server list..."; - - serverListMutex.lock(); - serverList.clear(); - - QSqlQuery query(servatriceDatabaseInterface->getDatabase()); - query.prepare("select id, ssl_cert, hostname, address, game_port, control_port from " + dbPrefix + "_servers order by id asc"); - servatriceDatabaseInterface->execSqlQuery(query); - while (query.next()) { - ServerProperties prop(query.value(0).toInt(), QSslCertificate(query.value(1).toString().toAscii()), query.value(2).toString(), QHostAddress(query.value(3).toString()), query.value(4).toInt(), query.value(5).toInt()); - serverList.append(prop); - qDebug() << QString("#%1 CERT=%2 NAME=%3 IP=%4:%5 CPORT=%6").arg(prop.id).arg(QString(prop.cert.digest().toHex())).arg(prop.hostname).arg(prop.address.toString()).arg(prop.gamePort).arg(prop.controlPort); - } - - serverListMutex.unlock(); + qDebug() << "Updating server list..."; + + serverListMutex.lock(); + serverList.clear(); + + QSqlQuery query(servatriceDatabaseInterface->getDatabase()); + query.prepare("select id, ssl_cert, hostname, address, game_port, control_port from " + dbPrefix + "_servers order by id asc"); + servatriceDatabaseInterface->execSqlQuery(query); + while (query.next()) { + ServerProperties prop(query.value(0).toInt(), QSslCertificate(query.value(1).toString().toAscii()), query.value(2).toString(), QHostAddress(query.value(3).toString()), query.value(4).toInt(), query.value(5).toInt()); + serverList.append(prop); + qDebug() << QString("#%1 CERT=%2 NAME=%3 IP=%4:%5 CPORT=%6").arg(prop.id).arg(QString(prop.cert.digest().toHex())).arg(prop.hostname).arg(prop.address.toString()).arg(prop.gamePort).arg(prop.controlPort); + } + + serverListMutex.unlock(); } QList Servatrice::getServerList() const { - serverListMutex.lock(); - QList result = serverList; - serverListMutex.unlock(); - - return result; + serverListMutex.lock(); + QList result = serverList; + serverListMutex.unlock(); + + return result; } int Servatrice::getUsersWithAddress(const QHostAddress &address) const { - int result = 0; - QReadLocker locker(&clientsLock); - for (int i = 0; i < clients.size(); ++i) - if (static_cast(clients[i])->getPeerAddress() == address) - ++result; - return result; + int result = 0; + QReadLocker locker(&clientsLock); + for (int i = 0; i < clients.size(); ++i) + if (static_cast(clients[i])->getPeerAddress() == address) + ++result; + return result; } QList Servatrice::getUsersWithAddressAsList(const QHostAddress &address) const { - QList result; - QReadLocker locker(&clientsLock); - for (int i = 0; i < clients.size(); ++i) - if (static_cast(clients[i])->getPeerAddress() == address) - result.append(static_cast(clients[i])); - return result; + QList result; + QReadLocker locker(&clientsLock); + for (int i = 0; i < clients.size(); ++i) + if (static_cast(clients[i])->getPeerAddress() == address) + result.append(static_cast(clients[i])); + return result; } void Servatrice::updateLoginMessage() { - if (!servatriceDatabaseInterface->checkSql()) - return; - - QSqlQuery query(servatriceDatabaseInterface->getDatabase()); - query.prepare("select message from " + dbPrefix + "_servermessages where id_server = :id_server order by timest desc limit 1"); - query.bindValue(":id_server", serverId); - if (servatriceDatabaseInterface->execSqlQuery(query)) - if (query.next()) { - const QString newLoginMessage = query.value(0).toString(); - - loginMessageMutex.lock(); - loginMessage = newLoginMessage; - loginMessageMutex.unlock(); - - Event_ServerMessage event; - event.set_message(newLoginMessage.toStdString()); - SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); - QMapIterator usersIterator(users); - while (usersIterator.hasNext()) - usersIterator.next().value()->sendProtocolItem(*se); - delete se; - } + if (!servatriceDatabaseInterface->checkSql()) + return; + + QSqlQuery query(servatriceDatabaseInterface->getDatabase()); + query.prepare("select message from " + dbPrefix + "_servermessages where id_server = :id_server order by timest desc limit 1"); + query.bindValue(":id_server", serverId); + if (servatriceDatabaseInterface->execSqlQuery(query)) + if (query.next()) { + const QString newLoginMessage = query.value(0).toString(); + + loginMessageMutex.lock(); + loginMessage = newLoginMessage; + loginMessageMutex.unlock(); + + Event_ServerMessage event; + event.set_message(newLoginMessage.toStdString()); + SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); + QMapIterator usersIterator(users); + while (usersIterator.hasNext()) + usersIterator.next().value()->sendProtocolItem(*se); + delete se; + } } void Servatrice::statusUpdate() { - if (!servatriceDatabaseInterface->checkSql()) - return; - - const int uc = getUsersCount(); // for correct mutex locking order - const int gc = getGamesCount(); - - uptime += statusUpdateClock->interval() / 1000; - - txBytesMutex.lock(); - quint64 tx = txBytes; - txBytes = 0; - txBytesMutex.unlock(); - rxBytesMutex.lock(); - quint64 rx = rxBytes; - rxBytes = 0; - rxBytesMutex.unlock(); - - QSqlQuery query(servatriceDatabaseInterface->getDatabase()); - query.prepare("insert into " + dbPrefix + "_uptime (id_server, timest, uptime, users_count, games_count, tx_bytes, rx_bytes) values(:id, NOW(), :uptime, :users_count, :games_count, :tx, :rx)"); - query.bindValue(":id", serverId); - query.bindValue(":uptime", uptime); - query.bindValue(":users_count", uc); - query.bindValue(":games_count", gc); - query.bindValue(":tx", tx); - query.bindValue(":rx", rx); - servatriceDatabaseInterface->execSqlQuery(query); + if (!servatriceDatabaseInterface->checkSql()) + return; + + const int uc = getUsersCount(); // for correct mutex locking order + const int gc = getGamesCount(); + + uptime += statusUpdateClock->interval() / 1000; + + txBytesMutex.lock(); + quint64 tx = txBytes; + txBytes = 0; + txBytesMutex.unlock(); + rxBytesMutex.lock(); + quint64 rx = rxBytes; + rxBytes = 0; + rxBytesMutex.unlock(); + + QSqlQuery query(servatriceDatabaseInterface->getDatabase()); + query.prepare("insert into " + dbPrefix + "_uptime (id_server, timest, uptime, users_count, games_count, tx_bytes, rx_bytes) values(:id, NOW(), :uptime, :users_count, :games_count, :tx, :rx)"); + query.bindValue(":id", serverId); + query.bindValue(":uptime", uptime); + query.bindValue(":users_count", uc); + query.bindValue(":games_count", gc); + query.bindValue(":tx", tx); + query.bindValue(":rx", rx); + servatriceDatabaseInterface->execSqlQuery(query); } void Servatrice::scheduleShutdown(const QString &reason, int minutes) { - shutdownReason = reason; - shutdownMinutes = minutes + 1; - if (minutes > 0) { - shutdownTimer = new QTimer; - connect(shutdownTimer, SIGNAL(timeout()), this, SLOT(shutdownTimeout())); - shutdownTimer->start(60000); - } - shutdownTimeout(); + shutdownReason = reason; + shutdownMinutes = minutes + 1; + if (minutes > 0) { + shutdownTimer = new QTimer; + connect(shutdownTimer, SIGNAL(timeout()), this, SLOT(shutdownTimeout())); + shutdownTimer->start(60000); + } + shutdownTimeout(); } void Servatrice::incTxBytes(quint64 num) { - txBytesMutex.lock(); - txBytes += num; - txBytesMutex.unlock(); + txBytesMutex.lock(); + txBytes += num; + txBytesMutex.unlock(); } void Servatrice::incRxBytes(quint64 num) { - rxBytesMutex.lock(); - rxBytes += num; - rxBytesMutex.unlock(); + rxBytesMutex.lock(); + rxBytes += num; + rxBytesMutex.unlock(); } void Servatrice::shutdownTimeout() { - --shutdownMinutes; - - SessionEvent *se; - if (shutdownMinutes) { - Event_ServerShutdown event; - event.set_reason(shutdownReason.toStdString()); - event.set_minutes(shutdownMinutes); - se = Server_ProtocolHandler::prepareSessionEvent(event); - } else { - Event_ConnectionClosed event; - event.set_reason(Event_ConnectionClosed::SERVER_SHUTDOWN); - se = Server_ProtocolHandler::prepareSessionEvent(event); - } - - clientsLock.lockForRead(); - for (int i = 0; i < clients.size(); ++i) - clients[i]->sendProtocolItem(*se); - clientsLock.unlock(); - delete se; - - if (!shutdownMinutes) - deleteLater(); + --shutdownMinutes; + + SessionEvent *se; + if (shutdownMinutes) { + Event_ServerShutdown event; + event.set_reason(shutdownReason.toStdString()); + event.set_minutes(shutdownMinutes); + se = Server_ProtocolHandler::prepareSessionEvent(event); + } else { + Event_ConnectionClosed event; + event.set_reason(Event_ConnectionClosed::SERVER_SHUTDOWN); + se = Server_ProtocolHandler::prepareSessionEvent(event); + } + + clientsLock.lockForRead(); + for (int i = 0; i < clients.size(); ++i) + clients[i]->sendProtocolItem(*se); + clientsLock.unlock(); + delete se; + + if (!shutdownMinutes) + deleteLater(); } bool Servatrice::islConnectionExists(int serverId) const { - // Only call with islLock locked at least for reading - - return islInterfaces.contains(serverId); + // Only call with islLock locked at least for reading + + return islInterfaces.contains(serverId); } void Servatrice::addIslInterface(int serverId, IslInterface *interface) { - // Only call with islLock locked for writing - - islInterfaces.insert(serverId, interface); - connect(interface, SIGNAL(externalUserJoined(ServerInfo_User)), this, SLOT(externalUserJoined(ServerInfo_User))); - connect(interface, SIGNAL(externalUserLeft(QString)), this, SLOT(externalUserLeft(QString))); - connect(interface, SIGNAL(externalRoomUserJoined(int, ServerInfo_User)), this, SLOT(externalRoomUserJoined(int, ServerInfo_User))); - connect(interface, SIGNAL(externalRoomUserLeft(int, QString)), this, SLOT(externalRoomUserLeft(int, QString))); - connect(interface, SIGNAL(externalRoomSay(int, QString, QString)), this, SLOT(externalRoomSay(int, QString, QString))); - connect(interface, SIGNAL(externalRoomGameListChanged(int, ServerInfo_Game)), this, SLOT(externalRoomGameListChanged(int, ServerInfo_Game))); - connect(interface, SIGNAL(joinGameCommandReceived(Command_JoinGame, int, int, int, qint64)), this, SLOT(externalJoinGameCommandReceived(Command_JoinGame, int, int, int, qint64))); - connect(interface, SIGNAL(gameCommandContainerReceived(CommandContainer, int, int, qint64)), this, SLOT(externalGameCommandContainerReceived(CommandContainer, int, int, qint64))); - connect(interface, SIGNAL(responseReceived(Response, qint64)), this, SLOT(externalResponseReceived(Response, qint64))); - connect(interface, SIGNAL(gameEventContainerReceived(GameEventContainer, qint64)), this, SLOT(externalGameEventContainerReceived(GameEventContainer, qint64))); + // Only call with islLock locked for writing + + islInterfaces.insert(serverId, interface); + connect(interface, SIGNAL(externalUserJoined(ServerInfo_User)), this, SLOT(externalUserJoined(ServerInfo_User))); + connect(interface, SIGNAL(externalUserLeft(QString)), this, SLOT(externalUserLeft(QString))); + connect(interface, SIGNAL(externalRoomUserJoined(int, ServerInfo_User)), this, SLOT(externalRoomUserJoined(int, ServerInfo_User))); + connect(interface, SIGNAL(externalRoomUserLeft(int, QString)), this, SLOT(externalRoomUserLeft(int, QString))); + connect(interface, SIGNAL(externalRoomSay(int, QString, QString)), this, SLOT(externalRoomSay(int, QString, QString))); + connect(interface, SIGNAL(externalRoomGameListChanged(int, ServerInfo_Game)), this, SLOT(externalRoomGameListChanged(int, ServerInfo_Game))); + connect(interface, SIGNAL(joinGameCommandReceived(Command_JoinGame, int, int, int, qint64)), this, SLOT(externalJoinGameCommandReceived(Command_JoinGame, int, int, int, qint64))); + connect(interface, SIGNAL(gameCommandContainerReceived(CommandContainer, int, int, qint64)), this, SLOT(externalGameCommandContainerReceived(CommandContainer, int, int, qint64))); + connect(interface, SIGNAL(responseReceived(Response, qint64)), this, SLOT(externalResponseReceived(Response, qint64))); + connect(interface, SIGNAL(gameEventContainerReceived(GameEventContainer, qint64)), this, SLOT(externalGameEventContainerReceived(GameEventContainer, qint64))); } void Servatrice::removeIslInterface(int serverId) { - // Only call with islLock locked for writing - - // XXX we probably need to delete everything that belonged to it... - islInterfaces.remove(serverId); + // Only call with islLock locked for writing + + // XXX we probably need to delete everything that belonged to it... + islInterfaces.remove(serverId); } void Servatrice::doSendIslMessage(const IslMessage &msg, int serverId) { - QReadLocker locker(&islLock); - - if (serverId == -1) { - QMapIterator islIterator(islInterfaces); - while (islIterator.hasNext()) - islIterator.next().value()->transmitMessage(msg); - } else { - IslInterface *interface = islInterfaces.value(serverId); - if (interface) - interface->transmitMessage(msg); - } + QReadLocker locker(&islLock); + + if (serverId == -1) { + QMapIterator islIterator(islInterfaces); + while (islIterator.hasNext()) + islIterator.next().value()->transmitMessage(msg); + } else { + IslInterface *interface = islInterfaces.value(serverId); + if (interface) + interface->transmitMessage(msg); + } }