mutex fixes, server shutdown works again
This commit is contained in:
parent
d792c3ddc6
commit
671214c60e
9 changed files with 34 additions and 27 deletions
|
@ -9,7 +9,6 @@ LocalServerInterface::LocalServerInterface(LocalServer *_server)
|
||||||
|
|
||||||
LocalServerInterface::~LocalServerInterface()
|
LocalServerInterface::~LocalServerInterface()
|
||||||
{
|
{
|
||||||
prepareDestroy();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalServerInterface::transmitProtocolItem(const ServerMessage &item)
|
void LocalServerInterface::transmitProtocolItem(const ServerMessage &item)
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
Server::Server(QObject *parent)
|
Server::Server(QObject *parent)
|
||||||
: QObject(parent), nextGameId(0), nextReplayId(0)
|
: QObject(parent), nextGameId(0), nextReplayId(0), clientsLock(QReadWriteLock::Recursive)
|
||||||
{
|
{
|
||||||
qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game");
|
qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game");
|
||||||
qRegisterMetaType<ServerInfo_Room>("ServerInfo_Room");
|
qRegisterMetaType<ServerInfo_Room>("ServerInfo_Room");
|
||||||
|
@ -45,17 +45,17 @@ Server::~Server()
|
||||||
|
|
||||||
void Server::prepareDestroy()
|
void Server::prepareDestroy()
|
||||||
{
|
{
|
||||||
|
clientsLock.lockForWrite();
|
||||||
|
while (!clients.isEmpty())
|
||||||
|
clients.first()->prepareDestroy();
|
||||||
|
clientsLock.unlock();
|
||||||
|
|
||||||
roomsLock.lockForWrite();
|
roomsLock.lockForWrite();
|
||||||
QMapIterator<int, Server_Room *> roomIterator(rooms);
|
QMapIterator<int, Server_Room *> roomIterator(rooms);
|
||||||
while (roomIterator.hasNext())
|
while (roomIterator.hasNext())
|
||||||
delete roomIterator.next().value();
|
delete roomIterator.next().value();
|
||||||
rooms.clear();
|
rooms.clear();
|
||||||
roomsLock.unlock();
|
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)
|
AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr)
|
||||||
|
|
|
@ -307,6 +307,12 @@ void Server_Game::stopGameIfFinished()
|
||||||
|
|
||||||
Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions)
|
Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions)
|
||||||
{
|
{
|
||||||
|
{
|
||||||
|
QMapIterator<int, Server_Player *> playerIterator(players);
|
||||||
|
while (playerIterator.hasNext())
|
||||||
|
if (playerIterator.next().value()->getUserInfo()->name() == user->name())
|
||||||
|
return Response::RespContextError;
|
||||||
|
}
|
||||||
if (!(overrideRestrictions && (user->user_level() & ServerInfo_User::IsModerator))) {
|
if (!(overrideRestrictions && (user->user_level() & ServerInfo_User::IsModerator))) {
|
||||||
if ((_password != password) && !(spectator && !spectatorsNeedPassword))
|
if ((_password != password) && !(spectator && !spectatorsNeedPassword))
|
||||||
return Response::RespWrongPassword;
|
return Response::RespWrongPassword;
|
||||||
|
|
|
@ -98,9 +98,6 @@ Server_ProtocolHandler::~Server_ProtocolHandler()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is essentially the destructor, but it needs to be called from the
|
|
||||||
// child's destructor so that the server mutex does not get unlocked during
|
|
||||||
// finalization.
|
|
||||||
void Server_ProtocolHandler::prepareDestroy()
|
void Server_ProtocolHandler::prepareDestroy()
|
||||||
{
|
{
|
||||||
qDebug("Server_ProtocolHandler::prepareDestroy");
|
qDebug("Server_ProtocolHandler::prepareDestroy");
|
||||||
|
@ -146,6 +143,8 @@ void Server_ProtocolHandler::prepareDestroy()
|
||||||
r->gamesMutex.unlock();
|
r->gamesMutex.unlock();
|
||||||
}
|
}
|
||||||
server->roomsLock.unlock();
|
server->roomsLock.unlock();
|
||||||
|
|
||||||
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server_ProtocolHandler::playerRemovedFromGame(Server_Game *game)
|
void Server_ProtocolHandler::playerRemovedFromGame(Server_Game *game)
|
||||||
|
@ -437,7 +436,7 @@ void Server_ProtocolHandler::pingClockTimeout()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime())
|
if (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime())
|
||||||
deleteLater();
|
prepareDestroy();
|
||||||
++timeRunning;
|
++timeRunning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,7 +485,6 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
|
||||||
server->roomsLock.lockForRead();
|
server->roomsLock.lockForRead();
|
||||||
|
|
||||||
QMapIterator<int, Server_Room *> roomIterator(server->getRooms());
|
QMapIterator<int, Server_Room *> roomIterator(server->getRooms());
|
||||||
gameListMutex.lock();
|
|
||||||
while (roomIterator.hasNext()) {
|
while (roomIterator.hasNext()) {
|
||||||
Server_Room *room = roomIterator.next().value();
|
Server_Room *room = roomIterator.next().value();
|
||||||
room->gamesMutex.lock();
|
room->gamesMutex.lock();
|
||||||
|
@ -498,7 +496,10 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
|
||||||
for (int j = 0; j < gamePlayers.size(); ++j)
|
for (int j = 0; j < gamePlayers.size(); ++j)
|
||||||
if (gamePlayers[j]->getUserInfo()->name() == userInfo->name()) {
|
if (gamePlayers[j]->getUserInfo()->name() == userInfo->name()) {
|
||||||
gamePlayers[j]->setProtocolHandler(this);
|
gamePlayers[j]->setProtocolHandler(this);
|
||||||
|
|
||||||
|
gameListMutex.lock();
|
||||||
games.insert(game->getGameId(), QPair<int, int>(room->getId(), gamePlayers[j]->getPlayerId()));
|
games.insert(game->getGameId(), QPair<int, int>(room->getId(), gamePlayers[j]->getPlayerId()));
|
||||||
|
gameListMutex.unlock();
|
||||||
|
|
||||||
Event_GameJoined event1;
|
Event_GameJoined event1;
|
||||||
event1.set_game_id(game->getGameId());
|
event1.set_game_id(game->getGameId());
|
||||||
|
@ -526,7 +527,6 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
|
||||||
}
|
}
|
||||||
room->gamesMutex.unlock();
|
room->gamesMutex.unlock();
|
||||||
}
|
}
|
||||||
gameListMutex.unlock();
|
|
||||||
server->roomsLock.unlock();
|
server->roomsLock.unlock();
|
||||||
|
|
||||||
rc.setResponseExtension(re);
|
rc.setResponseExtension(re);
|
||||||
|
@ -777,11 +777,6 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGam
|
||||||
if (authState == NotLoggedIn)
|
if (authState == NotLoggedIn)
|
||||||
return Response::RespLoginNeeded;
|
return Response::RespLoginNeeded;
|
||||||
|
|
||||||
QMutexLocker locker(&gameListMutex);
|
|
||||||
|
|
||||||
if (games.contains(cmd.game_id()))
|
|
||||||
return Response::RespContextError;
|
|
||||||
|
|
||||||
room->gamesMutex.lock();
|
room->gamesMutex.lock();
|
||||||
Server_Game *g = room->getGames().value(cmd.game_id());
|
Server_Game *g = room->getGames().value(cmd.game_id());
|
||||||
if (!g) {
|
if (!g) {
|
||||||
|
@ -795,7 +790,9 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGam
|
||||||
if (result == Response::RespOk) {
|
if (result == Response::RespOk) {
|
||||||
Server_Player *player = g->addPlayer(this, cmd.spectator());
|
Server_Player *player = g->addPlayer(this, cmd.spectator());
|
||||||
|
|
||||||
|
gameListMutex.lock();
|
||||||
games.insert(cmd.game_id(), QPair<int, int>(room->getId(), player->getPlayerId()));
|
games.insert(cmd.game_id(), QPair<int, int>(room->getId(), player->getPlayerId()));
|
||||||
|
gameListMutex.unlock();
|
||||||
|
|
||||||
Event_GameJoined event1;
|
Event_GameJoined event1;
|
||||||
event1.set_game_id(g->getGameId());
|
event1.set_game_id(g->getGameId());
|
||||||
|
|
|
@ -95,7 +95,6 @@ protected:
|
||||||
bool acceptsUserListChanges;
|
bool acceptsUserListChanges;
|
||||||
bool acceptsRoomListChanges;
|
bool acceptsRoomListChanges;
|
||||||
|
|
||||||
void prepareDestroy();
|
|
||||||
int sessionId;
|
int sessionId;
|
||||||
private:
|
private:
|
||||||
QMutex gameListMutex;
|
QMutex gameListMutex;
|
||||||
|
@ -174,6 +173,8 @@ private slots:
|
||||||
void pingClockTimeout();
|
void pingClockTimeout();
|
||||||
signals:
|
signals:
|
||||||
void logDebugMessage(const QString &message, Server_ProtocolHandler *session);
|
void logDebugMessage(const QString &message, Server_ProtocolHandler *session);
|
||||||
|
public slots:
|
||||||
|
void prepareDestroy();
|
||||||
public:
|
public:
|
||||||
Server_ProtocolHandler(Server *_server, QObject *parent = 0);
|
Server_ProtocolHandler(Server *_server, QObject *parent = 0);
|
||||||
~Server_ProtocolHandler();
|
~Server_ProtocolHandler();
|
||||||
|
|
|
@ -128,7 +128,6 @@ int main(int argc, char *argv[])
|
||||||
loggerThread = new QThread;
|
loggerThread = new QThread;
|
||||||
logger = new ServerLogger;
|
logger = new ServerLogger;
|
||||||
logger->moveToThread(loggerThread);
|
logger->moveToThread(loggerThread);
|
||||||
QObject::connect(logger, SIGNAL(destroyed()), loggerThread, SLOT(quit()));
|
|
||||||
|
|
||||||
loggerThread->start();
|
loggerThread->start();
|
||||||
QMetaObject::invokeMethod(logger, "startLog", Qt::BlockingQueuedConnection, Q_ARG(QString, settings->value("server/logfile").toString()));
|
QMetaObject::invokeMethod(logger, "startLog", Qt::BlockingQueuedConnection, Q_ARG(QString, settings->value("server/logfile").toString()));
|
||||||
|
|
|
@ -82,6 +82,8 @@ class Servatrice : public Server
|
||||||
private slots:
|
private slots:
|
||||||
void statusUpdate();
|
void statusUpdate();
|
||||||
void shutdownTimeout();
|
void shutdownTimeout();
|
||||||
|
public slots:
|
||||||
|
void scheduleShutdown(const QString &reason, int minutes);
|
||||||
public:
|
public:
|
||||||
mutable QMutex dbMutex;
|
mutable QMutex dbMutex;
|
||||||
Servatrice(QSettings *_settings, QObject *parent = 0);
|
Servatrice(QSettings *_settings, QObject *parent = 0);
|
||||||
|
@ -110,7 +112,6 @@ public:
|
||||||
QMap<QString, ServerInfo_User> getIgnoreList(const QString &name);
|
QMap<QString, ServerInfo_User> getIgnoreList(const QString &name);
|
||||||
bool isInBuddyList(const QString &whoseList, const QString &who);
|
bool isInBuddyList(const QString &whoseList, const QString &who);
|
||||||
bool isInIgnoreList(const QString &whoseList, const QString &who);
|
bool isInIgnoreList(const QString &whoseList, const QString &who);
|
||||||
void scheduleShutdown(const QString &reason, int minutes);
|
|
||||||
void incTxBytes(quint64 num);
|
void incTxBytes(quint64 num);
|
||||||
void incRxBytes(quint64 num);
|
void incRxBytes(quint64 num);
|
||||||
int getUserIdInDB(const QString &name);
|
int getUserIdInDB(const QString &name);
|
||||||
|
|
|
@ -16,6 +16,8 @@ ServerLogger::ServerLogger(QObject *parent)
|
||||||
ServerLogger::~ServerLogger()
|
ServerLogger::~ServerLogger()
|
||||||
{
|
{
|
||||||
flushBuffer();
|
flushBuffer();
|
||||||
|
// This does not work with the destroyed() signal as this destructor is called after the main event loop is done.
|
||||||
|
thread()->quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerLogger::startLog(const QString &logFileName)
|
void ServerLogger::startLog(const QString &logFileName)
|
||||||
|
|
|
@ -60,8 +60,9 @@ static const int protocolVersion = 13;
|
||||||
ServerSocketInterface::ServerSocketInterface(Servatrice *_server, QTcpSocket *_socket, QObject *parent)
|
ServerSocketInterface::ServerSocketInterface(Servatrice *_server, QTcpSocket *_socket, QObject *parent)
|
||||||
: Server_ProtocolHandler(_server, parent), servatrice(_server), socket(_socket), messageInProgress(false)
|
: Server_ProtocolHandler(_server, parent), servatrice(_server), socket(_socket), messageInProgress(false)
|
||||||
{
|
{
|
||||||
|
bool success = true;
|
||||||
|
|
||||||
connect(socket, SIGNAL(readyRead()), this, SLOT(readClient()));
|
connect(socket, SIGNAL(readyRead()), this, SLOT(readClient()));
|
||||||
connect(socket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
|
|
||||||
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(catchSocketError(QAbstractSocket::SocketError)));
|
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(catchSocketError(QAbstractSocket::SocketError)));
|
||||||
connect(this, SIGNAL(outputBufferChanged()), this, SLOT(flushOutputBuffer()), Qt::QueuedConnection);
|
connect(this, SIGNAL(outputBufferChanged()), this, SLOT(flushOutputBuffer()), Qt::QueuedConnection);
|
||||||
|
|
||||||
|
@ -81,18 +82,19 @@ ServerSocketInterface::ServerSocketInterface(Servatrice *_server, QTcpSocket *_s
|
||||||
sendProtocolItem(*se);
|
sendProtocolItem(*se);
|
||||||
delete se;
|
delete se;
|
||||||
|
|
||||||
deleteLater();
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
server->addClient(this);
|
server->addClient(this);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
prepareDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerSocketInterface::~ServerSocketInterface()
|
ServerSocketInterface::~ServerSocketInterface()
|
||||||
{
|
{
|
||||||
logger->logMessage("ServerSocketInterface destructor", this);
|
logger->logMessage("ServerSocketInterface destructor", this);
|
||||||
|
|
||||||
prepareDestroy();
|
|
||||||
|
|
||||||
flushOutputBuffer();
|
flushOutputBuffer();
|
||||||
delete socket;
|
delete socket;
|
||||||
socket = 0;
|
socket = 0;
|
||||||
|
@ -143,7 +145,7 @@ void ServerSocketInterface::catchSocketError(QAbstractSocket::SocketError socket
|
||||||
{
|
{
|
||||||
qDebug() << "Socket error:" << socketError;
|
qDebug() << "Socket error:" << socketError;
|
||||||
|
|
||||||
deleteLater();
|
prepareDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerSocketInterface::transmitProtocolItem(const ServerMessage &item)
|
void ServerSocketInterface::transmitProtocolItem(const ServerMessage &item)
|
||||||
|
@ -623,7 +625,7 @@ Response::ResponseCode ServerSocketInterface::cmdBanFromServer(const Command_Ban
|
||||||
for (int i = 0; i < userList.size(); ++i) {
|
for (int i = 0; i < userList.size(); ++i) {
|
||||||
SessionEvent *se = userList[i]->prepareSessionEvent(event);
|
SessionEvent *se = userList[i]->prepareSessionEvent(event);
|
||||||
userList[i]->sendProtocolItem(*se);
|
userList[i]->sendProtocolItem(*se);
|
||||||
userList[i]->deleteLater();
|
userList[i]->prepareDestroy();
|
||||||
delete se;
|
delete se;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue