changed a lot of thread locking code in the server, rooms are working with ISL now

This commit is contained in:
Max-Wilhelm Bruker 2012-03-17 16:09:00 +01:00
parent 572e4eaafa
commit c23af44749
16 changed files with 449 additions and 221 deletions

View file

@ -16,4 +16,5 @@ message ServerInfo_Game {
optional bool spectators_need_password = 13;
optional uint32 spectators_count = 14;
optional uint32 start_time = 15;
optional sint32 server_id = 16 [default = -1];
}

View file

@ -32,10 +32,11 @@
#include <QDebug>
Server::Server(QObject *parent)
: QObject(parent), serverMutex(QMutex::Recursive), nextGameId(0), nextReplayId(0)
: QObject(parent), nextGameId(0), nextReplayId(0)
{
qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game");
qRegisterMetaType<ServerInfo_Room>("ServerInfo_Room");
qRegisterMetaType<ServerInfo_User>("ServerInfo_User");
}
Server::~Server()
@ -44,22 +45,26 @@ Server::~Server()
void Server::prepareDestroy()
{
QMutexLocker locker(&serverMutex);
while (!clients.isEmpty())
delete clients.takeFirst();
roomsLock.lockForWrite();
QMapIterator<int, Server_Room *> roomIterator(rooms);
while (roomIterator.hasNext())
delete roomIterator.next().value();
rooms.clear();
roomsLock.unlock();
clientsLock.lockForWrite();
while (!clients.isEmpty())
delete clients.takeFirst();
clientsLock.unlock();
}
AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr)
{
QMutexLocker locker(&serverMutex);
if (name.size() > 35)
name = name.left(35);
QWriteLocker locker(&clientsLock);
AuthenticationResult authState = checkUserPassword(session, name, password, reasonStr);
if ((authState == NotLoggedIn) || (authState == UserIsBanned))
return authState;
@ -113,13 +118,13 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString
void Server::addClient(Server_ProtocolHandler *client)
{
QMutexLocker locker(&serverMutex);
QWriteLocker locker(&clientsLock);
clients << client;
}
void Server::removeClient(Server_ProtocolHandler *client)
{
QMutexLocker locker(&serverMutex);
QWriteLocker locker(&clientsLock);
clients.removeAt(clients.indexOf(client));
ServerInfo_User *data = client->getUserInfo();
if (data) {
@ -142,34 +147,90 @@ void Server::removeClient(Server_ProtocolHandler *client)
qDebug() << "Server::removeClient:" << clients.size() << "clients; " << users.size() << "users left";
}
void Server::externalUserJoined(ServerInfo_User userInfo)
void Server::externalUserJoined(const ServerInfo_User &userInfo)
{
// This function is always called from the main thread via signal/slot.
QMutexLocker locker(&serverMutex);
QWriteLocker locker(&clientsLock);
externalUsers.insert(QString::fromStdString(userInfo.name()), new Server_RemoteUserInterface(this, ServerInfo_User_Container(userInfo)));
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;
}
void Server::externalUserLeft(QString userName)
void Server::externalUserLeft(const QString &userName)
{
// This function is always called from the main thread via signal/slot.
QMutexLocker locker(&serverMutex);
QWriteLocker locker(&clientsLock);
delete externalUsers.take(userName);
Event_UserLeft event;
event.set_name(userName.toStdString());
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsUserListChanges())
clients[i]->sendProtocolItem(*se);
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);
}
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);
}
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);
}
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);
}
void Server::broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl)
@ -179,11 +240,11 @@ void Server::broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
serverMutex.lock();
clientsLock.lockForRead();
for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsRoomListChanges())
clients[i]->sendProtocolItem(*se);
serverMutex.unlock();
clientsLock.unlock();
if (sendToIsl)
sendIslMessage(*se);
@ -193,25 +254,26 @@ void Server::broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl
void Server::addRoom(Server_Room *newRoom)
{
QMutexLocker locker(&serverMutex);
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
{
QMutexLocker locker(&serverMutex);
QReadLocker locker(&clientsLock);
return users.size();
}
int Server::getGamesCount() const
{
int result = 0;
QMutexLocker locker(&serverMutex);
QReadLocker locker(&roomsLock);
QMapIterator<int, Server_Room *> roomIterator(rooms);
while (roomIterator.hasNext()) {
Server_Room *room = roomIterator.next().value();
QMutexLocker roomLocker(&room->roomMutex);
QMutexLocker roomLocker(&room->gamesMutex);
result += room->getGames().size();
}
return result;

View file

@ -5,8 +5,11 @@
#include <QStringList>
#include <QMap>
#include <QMutex>
#include <QReadWriteLock>
#include <QMetaType>
#include "pb/serverinfo_user.pb.h"
#include "pb/serverinfo_room.pb.h"
#include "pb/serverinfo_game.pb.h"
class Server_Game;
class Server_Room;
@ -29,7 +32,7 @@ signals:
private slots:
void broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl = false);
public:
mutable QMutex serverMutex;
mutable QReadWriteLock clientsLock, roomsLock;
Server(QObject *parent = 0);
~Server();
AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reason);
@ -67,9 +70,12 @@ public:
void removeExternalUser(const QString &userName);
const QMap<QString, Server_AbstractUserInterface *> &getExternalUsers() const { return externalUsers; }
protected slots:
void externalUserJoined(ServerInfo_User userInfo);
void externalUserLeft(QString userName);
void externalRoomUpdated(ServerInfo_Room roomInfo);
void externalUserJoined(const ServerInfo_User &userInfo);
void externalUserLeft(const QString &userName);
void externalRoomUserJoined(int roomId, const ServerInfo_User &userInfo);
void externalRoomUserLeft(int roomId, const QString &userName);
void externalRoomSay(int roomId, const QString &userName, const QString &message);
void externalRoomGameListChanged(int roomId, const ServerInfo_Game &gameInfo);
protected:
void prepareDestroy();
QList<Server_ProtocolHandler *> clients;
@ -95,4 +101,8 @@ protected:
virtual void doSendIslMessage(const IslMessage &msg, int serverId) { }
};
Q_DECLARE_METATYPE(ServerInfo_User)
Q_DECLARE_METATYPE(ServerInfo_Room)
Q_DECLARE_METATYPE(ServerInfo_Game)
#endif

View file

@ -65,7 +65,7 @@ Server_Game::Server_Game(Server_ProtocolHandler *_creator, int _gameId, const QS
Server_Game::~Server_Game()
{
room->roomMutex.lock();
room->gamesMutex.lock();
gameMutex.lock();
sendGameEventContainer(prepareGameEvent(Event_GameClosed(), -1));
@ -80,7 +80,7 @@ Server_Game::~Server_Game()
creatorInfo = 0;
gameMutex.unlock();
room->roomMutex.unlock();
room->gamesMutex.unlock();
currentReplay->set_duration_seconds(secondsElapsed - startTimeOfThisGame);
replayList.append(currentReplay);
@ -371,7 +371,6 @@ Server_Player *Server_Game::addPlayer(Server_ProtocolHandler *handler, bool spec
void Server_Game::removePlayer(Server_Player *player)
{
QMutexLocker roomLocker(&room->roomMutex);
QMutexLocker locker(&gameMutex);
players.remove(player->getPlayerId());
@ -461,7 +460,6 @@ void Server_Game::unattachCards(GameEventStorage &ges, Server_Player *player)
bool Server_Game::kickPlayer(int playerId)
{
QMutexLocker roomLocker(&room->roomMutex);
QMutexLocker locker(&gameMutex);
Server_Player *playerToKick = players.value(playerId);

View file

@ -89,7 +89,7 @@
#include <google/protobuf/descriptor.h>
Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, QObject *parent)
: QObject(parent), Server_AbstractUserInterface(_server), authState(NotLoggedIn), acceptsUserListChanges(false), acceptsRoomListChanges(false), sessionId(-1), timeRunning(0), lastDataReceived(0), gameListMutex(QMutex::Recursive)
: QObject(parent), Server_AbstractUserInterface(_server), authState(NotLoggedIn), acceptsUserListChanges(false), acceptsRoomListChanges(false), sessionId(-1), timeRunning(0), lastDataReceived(0)
{
connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout()));
}
@ -103,7 +103,6 @@ Server_ProtocolHandler::~Server_ProtocolHandler()
// finalization.
void Server_ProtocolHandler::prepareDestroy()
{
QMutexLocker locker(&server->serverMutex);
qDebug("Server_ProtocolHandler::prepareDestroy");
server->removeClient(this);
@ -113,20 +112,40 @@ void Server_ProtocolHandler::prepareDestroy()
roomIterator.next().value()->removeClient(this);
gameListMutex.lock();
QMapIterator<int, QPair<Server_Game *, Server_Player *> > gameIterator(games);
QMap<int, QPair<int, int> > tempGames(games);
gameListMutex.unlock();
server->roomsLock.lockForRead();
QMapIterator<int, QPair<int, int> > gameIterator(tempGames);
while (gameIterator.hasNext()) {
gameIterator.next();
Server_Game *g = gameIterator.value().first;
Server_Player *p = gameIterator.value().second;
Server_Room *r = server->getRooms().value(gameIterator.value().first);
if (!r)
continue;
r->gamesMutex.lock();
Server_Game *g = r->getGames().value(gameIterator.key());
if (!g) {
r->gamesMutex.unlock();
continue;
}
g->gameMutex.lock();
Server_Player *p = g->getPlayer(gameIterator.value().second);
if (!p) {
g->gameMutex.unlock();
r->gamesMutex.unlock();
continue;
}
if ((authState == UnknownUser) || p->getSpectator())
g->removePlayer(p);
else
p->setProtocolHandler(0);
g->gameMutex.unlock();
r->gamesMutex.unlock();
}
gameListMutex.unlock();
server->roomsLock.unlock();
}
void Server_ProtocolHandler::playerRemovedFromGame(Server_Game *game)
@ -214,12 +233,11 @@ Response::ResponseCode Server_ProtocolHandler::processRoomCommandContainer(const
if (authState == NotLoggedIn)
return Response::RespLoginNeeded;
QReadLocker locker(&server->roomsLock);
Server_Room *room = rooms.value(cont.room_id(), 0);
if (!room)
return Response::RespNotInRoom;
QMutexLocker locker(&room->roomMutex);
Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.room_command_size() - 1; i >= 0; --i) {
Response::ResponseCode resp = Response::RespInvalidCommand;
@ -245,16 +263,34 @@ Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const
gameListMutex.lock();
if (!games.contains(cont.game_id())) {
qDebug() << "invalid game";
gameListMutex.unlock();
return Response::RespNotInRoom;
}
QPair<Server_Game *, Server_Player *> gamePair = games.value(cont.game_id());
Server_Game *game = gamePair.first;
Server_Player *player = gamePair.second;
QMutexLocker locker(&game->gameMutex);
const QPair<int, int> roomIdAndPlayerId = games.value(cont.game_id());
gameListMutex.unlock();
server->roomsLock.lockForRead();
Server_Room *room = server->getRooms().value(roomIdAndPlayerId.first);
if (!room) {
server->roomsLock.unlock();
return Response::RespNotInRoom;
}
room->gamesMutex.lock();
Server_Game *game = room->getGames().value(cont.game_id());
if (!game) {
room->gamesMutex.unlock();
server->roomsLock.unlock();
return Response::RespNotInRoom;
}
game->gameMutex.lock();
Server_Player *player = game->getPlayer(roomIdAndPlayerId.second);
if (!player) {
game->gameMutex.unlock();
room->gamesMutex.unlock();
server->roomsLock.unlock();
return Response::RespNotInRoom;
}
GameEventStorage ges;
Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.game_command_size() - 1; i >= 0; --i) {
@ -298,6 +334,11 @@ Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const
finalResponseCode = resp;
}
ges.sendToGame(game);
game->gameMutex.unlock();
room->gamesMutex.unlock();
server->roomsLock.unlock();
return finalResponseCode;
}
@ -400,13 +441,6 @@ void Server_ProtocolHandler::pingClockTimeout()
++timeRunning;
}
QPair<Server_Game *, Server_Player *> Server_ProtocolHandler::getGame(int gameId) const
{
if (games.contains(gameId))
return games.value(gameId);
return QPair<Server_Game *, Server_Player *>(0, 0);
}
Response::ResponseCode Server_ProtocolHandler::cmdPing(const Command_Ping & /*cmd*/, ResponseContainer & /*rc*/)
{
return Response::RespOk;
@ -449,13 +483,13 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
re->add_ignore_list()->CopyFrom(ignoreIterator.next().value());
}
server->serverMutex.lock();
server->roomsLock.lockForRead();
QMapIterator<int, Server_Room *> roomIterator(server->getRooms());
QMutexLocker gameListLocker(&gameListMutex);
gameListMutex.lock();
while (roomIterator.hasNext()) {
Server_Room *room = roomIterator.next().value();
room->roomMutex.lock();
room->gamesMutex.lock();
QMapIterator<int, Server_Game *> gameIterator(room->getGames());
while (gameIterator.hasNext()) {
Server_Game *game = gameIterator.next().value();
@ -464,7 +498,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
for (int j = 0; j < gamePlayers.size(); ++j)
if (gamePlayers[j]->getUserInfo()->name() == userInfo->name()) {
gamePlayers[j]->setProtocolHandler(this);
games.insert(game->getGameId(), QPair<Server_Game *, Server_Player *>(game, gamePlayers[j]));
games.insert(game->getGameId(), QPair<int, int>(room->getId(), gamePlayers[j]->getPlayerId()));
Event_GameJoined event1;
event1.set_game_id(game->getGameId());
@ -478,7 +512,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event1));
Event_GameStateChanged event2;
QListIterator<ServerInfo_Player> gameStateIterator(game->getGameState(gamePlayers[j]));
QListIterator<ServerInfo_Player> gameStateIterator(game->getGameState(gamePlayers[j], gamePlayers[j]->getSpectator() && game->getSpectatorsSeeEverything(), true));
while (gameStateIterator.hasNext())
event2.add_player_list()->CopyFrom(gameStateIterator.next());
event2.set_seconds_elapsed(game->getSecondsElapsed());
@ -490,9 +524,10 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
break;
}
}
room->roomMutex.unlock();
room->gamesMutex.unlock();
}
server->serverMutex.unlock();
gameListMutex.unlock();
server->roomsLock.unlock();
rc.setResponseExtension(re);
return Response::RespOk;
@ -503,7 +538,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdMessage(const Command_Message
if (authState == NotLoggedIn)
return Response::RespLoginNeeded;
QMutexLocker locker(&server->serverMutex);
QReadLocker locker(&server->clientsLock);
QString receiver = QString::fromStdString(cmd.user_name());
Server_AbstractUserInterface *userInterface = server->getUsers().value(receiver);
@ -532,22 +567,24 @@ Response::ResponseCode Server_ProtocolHandler::cmdGetGamesOfUser(const Command_G
if (authState == NotLoggedIn)
return Response::RespLoginNeeded;
server->serverMutex.lock();
server->clientsLock.lockForRead();
if (!server->getUsers().contains(QString::fromStdString(cmd.user_name())))
return Response::RespNameNotFound;
server->clientsLock.unlock();
Response_GetGamesOfUser *re = new Response_GetGamesOfUser;
server->roomsLock.lockForRead();
QMapIterator<int, Server_Room *> roomIterator(server->getRooms());
while (roomIterator.hasNext()) {
Server_Room *room = roomIterator.next().value();
room->roomMutex.lock();
room->gamesMutex.lock();
re->add_room_list()->CopyFrom(room->getInfo(false, true));
QListIterator<ServerInfo_Game> gameIterator(room->getGamesOfUser(QString::fromStdString(cmd.user_name())));
while (gameIterator.hasNext())
re->add_game_list()->CopyFrom(gameIterator.next());
room->roomMutex.unlock();
room->gamesMutex.unlock();
}
server->serverMutex.unlock();
server->roomsLock.unlock();
rc.setResponseExtension(re);
return Response::RespOk;
@ -564,7 +601,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdGetUserInfo(const Command_GetU
re->mutable_user_info()->CopyFrom(*userInfo);
else {
QMutexLocker locker(&server->serverMutex);
QReadLocker locker(&server->clientsLock);
ServerInfo_User_Container *infoSource;
if (server->getUsers().contains(userName))
@ -604,12 +641,11 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinRoom(const Command_JoinRoo
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;
QMutexLocker serverLocker(&server->serverMutex);
QMutexLocker roomLocker(&r->roomMutex);
r->addClient(this);
rooms.insert(r->getId(), r);
@ -630,14 +666,14 @@ Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUs
return Response::RespLoginNeeded;
Response_ListUsers *re = new Response_ListUsers;
server->serverMutex.lock();
server->clientsLock.lockForRead();
QMapIterator<QString, Server_ProtocolHandler *> userIterator = server->getUsers();
while (userIterator.hasNext())
re->add_user_list()->CopyFrom(userIterator.next().value()->copyUserInfo(false));
QMapIterator<QString, Server_AbstractUserInterface *> extIterator = server->getExternalUsers();
while (extIterator.hasNext())
re->add_user_list()->CopyFrom(extIterator.next().value()->copyUserInfo(false));
server->serverMutex.unlock();
server->clientsLock.unlock();
acceptsUserListChanges = true;
@ -675,7 +711,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdRoomSay(const Command_RoomSay
}
msg.replace(QChar('\n'), QChar(' '));
room->say(this, msg);
room->say(QString::fromStdString(userInfo->name()), msg);
return Response::RespOk;
}
@ -683,7 +719,9 @@ Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_Creat
{
if (authState == NotLoggedIn)
return Response::RespLoginNeeded;
QMutexLocker roomLocker(&room->gamesMutex);
if (server->getMaxGamesPerUser() > 0)
if (room->getGamesCreatedByUser(QString::fromStdString(userInfo->name())) >= server->getMaxGamesPerUser())
return Response::RespContextError;
@ -699,13 +737,14 @@ Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_Creat
Server_Game *game = new Server_Game(this, server->getNextGameId(), 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->moveToThread(room->thread());
QMutexLocker gameListLocker(&gameListMutex);
game->gameMutex.lock();
room->addGame(game);
Server_Player *creator = game->getPlayers().values().first();
games.insert(game->getGameId(), QPair<Server_Game *, Server_Player *>(game, creator));
gameListMutex.lock();
games.insert(game->getGameId(), QPair<int, int>(room->getId(), creator->getPlayerId()));
gameListMutex.unlock();
Event_GameJoined event1;
event1.set_game_id(game->getGameId());
@ -738,21 +777,25 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGam
if (authState == NotLoggedIn)
return Response::RespLoginNeeded;
QMutexLocker gameListLocker(&gameListMutex);
QMutexLocker locker(&gameListMutex);
if (games.contains(cmd.game_id()))
return Response::RespContextError;
room->gamesMutex.lock();
Server_Game *g = room->getGames().value(cmd.game_id());
if (!g)
if (!g) {
room->gamesMutex.unlock();
return Response::RespNameNotFound;
}
QMutexLocker locker(&g->gameMutex);
g->gameMutex.lock();
Response::ResponseCode result = g->checkJoin(userInfo, QString::fromStdString(cmd.password()), cmd.spectator(), cmd.override_restrictions());
if (result == Response::RespOk) {
Server_Player *player = g->addPlayer(this, cmd.spectator());
games.insert(cmd.game_id(), QPair<Server_Game *, Server_Player *>(g, player));
games.insert(cmd.game_id(), QPair<int, int>(room->getId(), player->getPlayerId()));
Event_GameJoined event1;
event1.set_game_id(g->getGameId());
@ -775,6 +818,10 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGam
event2.set_active_phase(g->getActivePhase());
rc.enqueuePostResponseItem(ServerMessage::GAME_EVENT_CONTAINER, g->prepareGameEvent(event2, -1));
}
g->gameMutex.unlock();
room->gamesMutex.unlock();
return result;
}

View file

@ -88,11 +88,9 @@ class Command_ShutdownServer;
class Server_ProtocolHandler : public QObject, public Server_AbstractUserInterface {
Q_OBJECT
protected:
QMap<int, QPair<Server_Game *, Server_Player *> > games;
QMap<int, QPair<int, int> > games; // gameId -> (roomId, playerId)
QMap<int, Server_Room *> rooms;
QPair<Server_Game *, Server_Player *> getGame(int gameId) const;
AuthenticationResult authState;
bool acceptsUserListChanges;
bool acceptsRoomListChanges;
@ -100,6 +98,8 @@ protected:
void prepareDestroy();
int sessionId;
private:
QMutex gameListMutex;
QList<int> messageSizeOverTime, messageCountOverTime;
int timeRunning, lastDataReceived;
QTimer *pingClock;
@ -175,8 +175,6 @@ private slots:
signals:
void logDebugMessage(const QString &message, Server_ProtocolHandler *session);
public:
QMutex gameListMutex;
Server_ProtocolHandler(Server *_server, QObject *parent = 0);
~Server_ProtocolHandler();
void playerRemovedFromGame(Server_Game *game);

View file

@ -10,22 +10,25 @@
#include <google/protobuf/descriptor.h>
Server_Room::Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent)
: QObject(parent), id(_id), name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage), gameTypes(_gameTypes), roomMutex(QMutex::Recursive)
: QObject(parent), id(_id), name(_name), description(_description), autoJoin(_autoJoin), joinMessage(_joinMessage), gameTypes(_gameTypes), gamesMutex(QMutex::Recursive)
{
connect(this, SIGNAL(gameListChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game)), Qt::QueuedConnection);
}
Server_Room::~Server_Room()
{
QMutexLocker locker(&roomMutex);
qDebug("Server_Room destructor");
gamesMutex.lock();
const QList<Server_Game *> gameList = games.values();
for (int i = 0; i < gameList.size(); ++i)
delete gameList[i];
games.clear();
gamesMutex.unlock();
usersLock.lockForWrite();
userList.clear();
usersLock.unlock();
}
Server *Server_Room::getServer() const
@ -35,12 +38,8 @@ Server *Server_Room::getServer() const
ServerInfo_Room Server_Room::getInfo(bool complete, bool showGameTypes, bool updating, bool includeExternalData) const
{
QMutexLocker locker(&roomMutex);
ServerInfo_Room result;
result.set_room_id(id);
result.set_game_count(games.size() + externalGames.size());
result.set_player_count(userList.size() + externalUsers.size());
if (!updating) {
result.set_name(name.toStdString());
@ -48,6 +47,8 @@ ServerInfo_Room Server_Room::getInfo(bool complete, bool showGameTypes, bool upd
result.set_auto_join(autoJoin);
}
gamesMutex.lock();
result.set_game_count(games.size() + externalGames.size());
if (complete) {
QMapIterator<int, Server_Game *> gameIterator(games);
while (gameIterator.hasNext())
@ -57,7 +58,12 @@ ServerInfo_Room Server_Room::getInfo(bool complete, bool showGameTypes, bool upd
while (externalGameIterator.hasNext())
result.add_game_list()->CopyFrom(externalGameIterator.next().value());
}
}
gamesMutex.unlock();
usersLock.lockForRead();
result.set_player_count(userList.size() + externalUsers.size());
if (complete) {
for (int i = 0; i < userList.size(); ++i)
result.add_user_list()->CopyFrom(userList[i]->copyUserInfo(false));
if (includeExternalData) {
@ -66,6 +72,8 @@ ServerInfo_Room Server_Room::getInfo(bool complete, bool showGameTypes, bool upd
result.add_user_list()->CopyFrom(externalUserIterator.next().value().copyUserInfo(false));
}
}
usersLock.unlock();
if (complete || showGameTypes)
for (int i = 0; i < gameTypes.size(); ++i) {
ServerInfo_GameType *gameTypeInfo = result.add_gametype_list();
@ -90,18 +98,18 @@ void Server_Room::addClient(Server_ProtocolHandler *client)
event.mutable_user_info()->CopyFrom(client->copyUserInfo(false));
sendRoomEvent(prepareRoomEvent(event));
roomMutex.lock();
usersLock.lockForWrite();
userList.append(client);
roomMutex.unlock();
usersLock.unlock();
emit roomInfoChanged(getInfo(false, false, true));
}
void Server_Room::removeClient(Server_ProtocolHandler *client)
{
roomMutex.lock();
usersLock.lockForWrite();
userList.removeAt(userList.indexOf(client));
roomMutex.unlock();
usersLock.unlock();
Event_LeaveRoom event;
event.set_name(client->getUserInfo()->name());
@ -112,23 +120,25 @@ void Server_Room::removeClient(Server_ProtocolHandler *client)
void Server_Room::addExternalUser(const ServerInfo_User &userInfo)
{
// This function is always called from the Server thread with server->roomsMutex locked.
ServerInfo_User_Container userInfoContainer(userInfo);
Event_JoinRoom event;
event.mutable_user_info()->CopyFrom(userInfoContainer.copyUserInfo(false));
sendRoomEvent(prepareRoomEvent(event), false);
roomMutex.lock();
usersLock.lockForWrite();
externalUsers.insert(QString::fromStdString(userInfo.name()), userInfoContainer);
roomMutex.unlock();
usersLock.unlock();
emit roomInfoChanged(getInfo(false, false, true));
}
void Server_Room::removeExternalUser(const QString &name)
{
roomMutex.lock();
// This function is always called from the Server thread with server->roomsMutex locked.
usersLock.lockForWrite();
externalUsers.remove(name);
roomMutex.unlock();
usersLock.unlock();
Event_LeaveRoom event;
event.set_name(name.toStdString());
@ -137,20 +147,34 @@ void Server_Room::removeExternalUser(const QString &name)
emit roomInfoChanged(getInfo(false, false, true));
}
void Server_Room::say(Server_ProtocolHandler *client, const QString &s)
void Server_Room::updateExternalGameList(const ServerInfo_Game &gameInfo)
{
// This function is always called from the Server thread with server->roomsMutex locked.
gamesMutex.lock();
if (!gameInfo.has_player_count() && externalGames.contains(gameInfo.game_id()))
externalGames.remove(gameInfo.game_id());
else
externalGames.insert(gameInfo.game_id(), gameInfo);
gamesMutex.unlock();
broadcastGameListUpdate(gameInfo, false);
emit roomInfoChanged(getInfo(false, false, true));
}
void Server_Room::say(const QString &userName, const QString &s, bool sendToIsl)
{
Event_RoomSay event;
event.set_name(client->getUserInfo()->name());
event.set_name(userName.toStdString());
event.set_message(s.toStdString());
sendRoomEvent(prepareRoomEvent(event));
sendRoomEvent(prepareRoomEvent(event), sendToIsl);
}
void Server_Room::sendRoomEvent(RoomEvent *event, bool sendToIsl)
{
roomMutex.lock();
usersLock.lockForRead();
for (int i = 0; i < userList.size(); ++i)
userList[i]->sendProtocolItem(*event);
roomMutex.unlock();
usersLock.unlock();
if (sendToIsl)
static_cast<Server *>(parent())->sendIslMessage(*event);
@ -158,16 +182,16 @@ void Server_Room::sendRoomEvent(RoomEvent *event, bool sendToIsl)
delete event;
}
void Server_Room::broadcastGameListUpdate(ServerInfo_Game gameInfo)
void Server_Room::broadcastGameListUpdate(ServerInfo_Game gameInfo, bool sendToIsl)
{
Event_ListGames event;
event.add_game_list()->CopyFrom(gameInfo);
sendRoomEvent(prepareRoomEvent(event));
sendRoomEvent(prepareRoomEvent(event), sendToIsl);
}
void Server_Room::addGame(Server_Game *game)
{
// Lock roomMutex and gameMutex before calling this
// Lock gamesMutex and gameMutex before calling this
connect(game, SIGNAL(gameInfoChanged(ServerInfo_Game)), this, SLOT(broadcastGameListUpdate(ServerInfo_Game)));
games.insert(game->getGameId(), game);
@ -177,7 +201,7 @@ void Server_Room::addGame(Server_Game *game)
void Server_Room::removeGame(Server_Game *game)
{
// No need to lock roomMutex or gameMutex. This method is only
// No need to lock gamesMutex or gameMutex. This method is only
// called from ~Server_Game, which locks both mutexes anyway beforehand.
disconnect(game, 0, this, 0);
@ -189,7 +213,7 @@ void Server_Room::removeGame(Server_Game *game)
int Server_Room::getGamesCreatedByUser(const QString &userName) const
{
QMutexLocker locker(&roomMutex);
QMutexLocker locker(&gamesMutex);
QMapIterator<int, Server_Game *> gamesIterator(games);
int result = 0;
@ -201,6 +225,8 @@ int Server_Room::getGamesCreatedByUser(const QString &userName) const
QList<ServerInfo_Game> Server_Room::getGamesOfUser(const QString &userName) const
{
QMutexLocker locker(&gamesMutex);
QList<ServerInfo_Game> result;
QMapIterator<int, Server_Game *> gamesIterator(games);
while (gamesIterator.hasNext()) {

View file

@ -6,7 +6,7 @@
#include <QObject>
#include <QStringList>
#include <QMutex>
#include <QMetaType>
#include <QReadWriteLock>
#include "pb/serverinfo_room.pb.h"
#include "serverinfo_user_container.h"
@ -35,9 +35,10 @@ private:
QList<Server_ProtocolHandler *> userList;
QMap<QString, ServerInfo_User_Container> externalUsers;
private slots:
void broadcastGameListUpdate(ServerInfo_Game gameInfo);
void broadcastGameListUpdate(ServerInfo_Game gameInfo, bool sendToIsl = true);
public:
mutable QMutex roomMutex;
mutable QReadWriteLock usersLock;
mutable QMutex gamesMutex;
Server_Room(int _id, const QString &_name, const QString &_description, bool _autoJoin, const QString &_joinMessage, const QStringList &_gameTypes, Server *parent);
~Server_Room();
int getId() const { return id; }
@ -57,8 +58,10 @@ public:
void addExternalUser(const ServerInfo_User &userInfo);
void removeExternalUser(const QString &name);
const QMap<QString, ServerInfo_User_Container> &getExternalUsers() const { return externalUsers; }
void updateExternalGameList(const ServerInfo_Game &gameInfo);
void say(Server_ProtocolHandler *client, const QString &s);
void say(const QString &userName, const QString &s, bool sendToIsl = true);
void addGame(Server_Game *game);
void removeGame(Server_Game *game);
@ -67,7 +70,4 @@ public:
RoomEvent *prepareRoomEvent(const ::google::protobuf::Message &roomEvent);
};
Q_DECLARE_METATYPE(ServerInfo_Game)
Q_DECLARE_METATYPE(ServerInfo_Room)
#endif