Requested Cleanup

Corrected tab to 4 space (per request)
Moved regonly option under authentication ini location (per request)
This commit is contained in:
woogerboy21 2014-07-02 22:27:05 -04:00
parent d246fa39fe
commit 0a1fe7f5a8
5 changed files with 1274 additions and 1274 deletions

View file

@ -262,8 +262,8 @@ void MainWindow::loginError(Response::ResponseCode r, QString reasonStr, quint32
QMessageBox::critical(this, tr("Error"), tr("Invalid username.")); QMessageBox::critical(this, tr("Error"), tr("Invalid username."));
break; break;
case Response::RespRegistrationRequired: case Response::RespRegistrationRequired:
QMessageBox::critical(this, tr("Error"), tr("This server requires user registration.")); QMessageBox::critical(this, tr("Error"), tr("This server requires user registration."));
break; break;
default: default:
QMessageBox::critical(this, tr("Error"), tr("Unknown login error: %1").arg(static_cast<int>(r))); QMessageBox::critical(this, tr("Error"), tr("Unknown login error: %1").arg(static_cast<int>(r)));
} }

View file

@ -37,18 +37,18 @@
#include <QSettings> #include <QSettings>
Server::Server(bool _threaded, QObject *parent) Server::Server(bool _threaded, QObject *parent)
: QObject(parent), threaded(_threaded), nextLocalGameId(0) : QObject(parent), threaded(_threaded), nextLocalGameId(0)
{ {
qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game"); qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game");
qRegisterMetaType<ServerInfo_Room>("ServerInfo_Room"); qRegisterMetaType<ServerInfo_Room>("ServerInfo_Room");
qRegisterMetaType<ServerInfo_User>("ServerInfo_User"); qRegisterMetaType<ServerInfo_User>("ServerInfo_User");
qRegisterMetaType<CommandContainer>("CommandContainer"); qRegisterMetaType<CommandContainer>("CommandContainer");
qRegisterMetaType<Response>("Response"); qRegisterMetaType<Response>("Response");
qRegisterMetaType<GameEventContainer>("GameEventContainer"); qRegisterMetaType<GameEventContainer>("GameEventContainer");
qRegisterMetaType<IslMessage>("IslMessage"); qRegisterMetaType<IslMessage>("IslMessage");
qRegisterMetaType<Command_JoinGame>("Command_JoinGame"); qRegisterMetaType<Command_JoinGame>("Command_JoinGame");
connect(this, SIGNAL(sigSendIslMessage(IslMessage, int)), this, SLOT(doSendIslMessage(IslMessage, int)), Qt::QueuedConnection); connect(this, SIGNAL(sigSendIslMessage(IslMessage, int)), this, SLOT(doSendIslMessage(IslMessage, int)), Qt::QueuedConnection);
} }
Server::~Server() Server::~Server()
@ -57,540 +57,540 @@ Server::~Server()
void Server::prepareDestroy() void Server::prepareDestroy()
{ {
// dirty :( // dirty :(
if (threaded) { if (threaded) {
clientsLock.lockForRead(); clientsLock.lockForRead();
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
QMetaObject::invokeMethod(clients.at(i), "prepareDestroy", Qt::QueuedConnection); QMetaObject::invokeMethod(clients.at(i), "prepareDestroy", Qt::QueuedConnection);
clientsLock.unlock(); clientsLock.unlock();
bool done = false; bool done = false;
class SleeperThread : public QThread class SleeperThread : public QThread
{ {
public: public:
static void msleep(unsigned long msecs) { QThread::usleep(msecs); } static void msleep(unsigned long msecs) { QThread::usleep(msecs); }
}; };
do { do {
SleeperThread::msleep(10); SleeperThread::msleep(10);
clientsLock.lockForRead(); clientsLock.lockForRead();
if (clients.isEmpty()) if (clients.isEmpty())
done = true; done = true;
clientsLock.unlock(); clientsLock.unlock();
} while (!done); } while (!done);
} else { } else {
// no locking is needed in unthreaded mode // no locking is needed in unthreaded mode
while (!clients.isEmpty()) while (!clients.isEmpty())
clients.first()->prepareDestroy(); clients.first()->prepareDestroy();
} }
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();
} }
void Server::setDatabaseInterface(Server_DatabaseInterface *_databaseInterface) void Server::setDatabaseInterface(Server_DatabaseInterface *_databaseInterface)
{ {
connect(this, SIGNAL(endSession(qint64)), _databaseInterface, SLOT(endSession(qint64))); connect(this, SIGNAL(endSession(qint64)), _databaseInterface, SLOT(endSession(qint64)));
databaseInterfaces.insert(QThread::currentThread(), _databaseInterface); databaseInterfaces.insert(QThread::currentThread(), _databaseInterface);
} }
Server_DatabaseInterface *Server::getDatabaseInterface() const 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) AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr, int &secondsLeft)
{ {
if (name.size() > 35) if (name.size() > 35)
name = name.left(35); name = name.left(35);
Server_DatabaseInterface *databaseInterface = getDatabaseInterface(); Server_DatabaseInterface *databaseInterface = getDatabaseInterface();
QWriteLocker locker(&clientsLock); QWriteLocker locker(&clientsLock);
AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft); AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft);
if ((authState == NotLoggedIn) || (authState == UserIsBanned || authState == UsernameInvalid)) if ((authState == NotLoggedIn) || (authState == UserIsBanned || authState == UsernameInvalid))
return authState; return authState;
ServerInfo_User data = databaseInterface->getUserData(name, true); ServerInfo_User data = databaseInterface->getUserData(name, true);
data.set_address(session->getAddress().toStdString()); data.set_address(session->getAddress().toStdString());
name = QString::fromStdString(data.name()); // Compensate for case indifference name = QString::fromStdString(data.name()); // Compensate for case indifference
databaseInterface->lockSessionTables(); databaseInterface->lockSessionTables();
if (authState == PasswordRight) { if (authState == PasswordRight) {
if (users.contains(name) || databaseInterface->userSessionExists(name)) { if (users.contains(name) || databaseInterface->userSessionExists(name)) {
qDebug("Login denied: would overwrite old session"); qDebug("Login denied: would overwrite old session");
databaseInterface->unlockSessionTables(); databaseInterface->unlockSessionTables();
return WouldOverwriteOldSession; return WouldOverwriteOldSession;
} }
} else if (authState == UnknownUser) { } else if (authState == UnknownUser) {
// Change user name so that no two users have the same names, // Change user name so that no two users have the same names,
// don't interfere with registered user names though. // don't interfere with registered user names though.
QSettings *settings = new QSettings("servatrice.ini", QSettings::IniFormat); QSettings *settings = new QSettings("servatrice.ini", QSettings::IniFormat);
bool requireReg = settings->value("server/regonly").toBool(); bool requireReg = settings->value("authentication/regonly", 0).toBool();
if (requireReg) { if (requireReg) {
qDebug("Login denied: registration required"); qDebug("Login denied: registration required");
databaseInterface->unlockSessionTables(); databaseInterface->unlockSessionTables();
return RegistrationRequired; return RegistrationRequired;
} }
QString tempName = name; QString tempName = name;
int i = 0; int i = 0;
while (users.contains(tempName) || databaseInterface->userExists(tempName) || databaseInterface->userSessionExists(tempName)) while (users.contains(tempName) || databaseInterface->userExists(tempName) || databaseInterface->userSessionExists(tempName))
tempName = name + "_" + QString::number(++i); tempName = name + "_" + QString::number(++i);
name = tempName; name = tempName;
data.set_name(name.toStdString()); data.set_name(name.toStdString());
} }
users.insert(name, session); users.insert(name, session);
qDebug() << "Server::loginUser:" << session << "name=" << name; qDebug() << "Server::loginUser:" << session << "name=" << name;
data.set_session_id(databaseInterface->startSession(name, session->getAddress())); data.set_session_id(databaseInterface->startSession(name, session->getAddress()));
databaseInterface->unlockSessionTables(); databaseInterface->unlockSessionTables();
usersBySessionId.insert(data.session_id(), session); usersBySessionId.insert(data.session_id(), session);
qDebug() << "session id:" << data.session_id(); qDebug() << "session id:" << data.session_id();
session->setUserInfo(data); session->setUserInfo(data);
Event_UserJoined event; Event_UserJoined event;
event.mutable_user_info()->CopyFrom(session->copyUserInfo(false)); event.mutable_user_info()->CopyFrom(session->copyUserInfo(false));
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsUserListChanges()) if (clients[i]->getAcceptsUserListChanges())
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
delete se; delete se;
event.mutable_user_info()->CopyFrom(session->copyUserInfo(true, true, true)); event.mutable_user_info()->CopyFrom(session->copyUserInfo(true, true, true));
locker.unlock(); locker.unlock();
se = Server_ProtocolHandler::prepareSessionEvent(event); se = Server_ProtocolHandler::prepareSessionEvent(event);
sendIsl_SessionEvent(*se); sendIsl_SessionEvent(*se);
delete se; delete se;
return authState; return authState;
} }
void Server::addPersistentPlayer(const QString &userName, int roomId, int gameId, int playerId) void Server::addPersistentPlayer(const QString &userName, int roomId, int gameId, int playerId)
{ {
QWriteLocker locker(&persistentPlayersLock); QWriteLocker locker(&persistentPlayersLock);
persistentPlayers.insert(userName, PlayerReference(roomId, gameId, playerId)); persistentPlayers.insert(userName, PlayerReference(roomId, gameId, playerId));
} }
void Server::removePersistentPlayer(const QString &userName, int roomId, int gameId, int playerId) void Server::removePersistentPlayer(const QString &userName, int roomId, int gameId, int playerId)
{ {
QWriteLocker locker(&persistentPlayersLock); QWriteLocker locker(&persistentPlayersLock);
persistentPlayers.remove(userName, PlayerReference(roomId, gameId, playerId)); persistentPlayers.remove(userName, PlayerReference(roomId, gameId, playerId));
} }
QList<PlayerReference> Server::getPersistentPlayerReferences(const QString &userName) const QList<PlayerReference> Server::getPersistentPlayerReferences(const QString &userName) const
{ {
QReadLocker locker(&persistentPlayersLock); QReadLocker locker(&persistentPlayersLock);
return persistentPlayers.values(userName); return persistentPlayers.values(userName);
} }
Server_AbstractUserInterface *Server::findUser(const QString &userName) const Server_AbstractUserInterface *Server::findUser(const QString &userName) const
{ {
// Call this only with clientsLock set. // Call this only with clientsLock set.
Server_AbstractUserInterface *userHandler = users.value(userName); Server_AbstractUserInterface *userHandler = users.value(userName);
if (userHandler) if (userHandler)
return userHandler; return userHandler;
else else
return externalUsers.value(userName); return externalUsers.value(userName);
} }
void Server::addClient(Server_ProtocolHandler *client) void Server::addClient(Server_ProtocolHandler *client)
{ {
QWriteLocker locker(&clientsLock); QWriteLocker locker(&clientsLock);
clients << client; clients << client;
} }
void Server::removeClient(Server_ProtocolHandler *client) void Server::removeClient(Server_ProtocolHandler *client)
{ {
QWriteLocker locker(&clientsLock); QWriteLocker locker(&clientsLock);
clients.removeAt(clients.indexOf(client)); clients.removeAt(clients.indexOf(client));
ServerInfo_User *data = client->getUserInfo(); ServerInfo_User *data = client->getUserInfo();
if (data) { if (data) {
Event_UserLeft event; Event_UserLeft event;
event.set_name(data->name()); event.set_name(data->name());
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsUserListChanges()) if (clients[i]->getAcceptsUserListChanges())
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
sendIsl_SessionEvent(*se); sendIsl_SessionEvent(*se);
delete se; delete se;
users.remove(QString::fromStdString(data->name())); users.remove(QString::fromStdString(data->name()));
qDebug() << "Server::removeClient: name=" << QString::fromStdString(data->name()); qDebug() << "Server::removeClient: name=" << QString::fromStdString(data->name());
if (data->has_session_id()) { if (data->has_session_id()) {
const qint64 sessionId = data->session_id(); const qint64 sessionId = data->session_id();
usersBySessionId.remove(sessionId); usersBySessionId.remove(sessionId);
emit endSession(sessionId); emit endSession(sessionId);
qDebug() << "closed session id:" << sessionId; qDebug() << "closed session id:" << sessionId;
} }
} }
qDebug() << "Server::removeClient: removed" << (void *) client << ";" << clients.size() << "clients; " << users.size() << "users left"; qDebug() << "Server::removeClient: removed" << (void *) client << ";" << clients.size() << "clients; " << users.size() << "users left";
} }
void Server::externalUserJoined(const ServerInfo_User &userInfo) void Server::externalUserJoined(const ServerInfo_User &userInfo)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
clientsLock.lockForWrite(); clientsLock.lockForWrite();
Server_RemoteUserInterface *newUser = new Server_RemoteUserInterface(this, ServerInfo_User_Container(userInfo)); Server_RemoteUserInterface *newUser = new Server_RemoteUserInterface(this, ServerInfo_User_Container(userInfo));
externalUsers.insert(QString::fromStdString(userInfo.name()), newUser); externalUsers.insert(QString::fromStdString(userInfo.name()), newUser);
externalUsersBySessionId.insert(userInfo.session_id(), newUser); externalUsersBySessionId.insert(userInfo.session_id(), newUser);
Event_UserJoined event; Event_UserJoined event;
event.mutable_user_info()->CopyFrom(userInfo); event.mutable_user_info()->CopyFrom(userInfo);
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsUserListChanges()) if (clients[i]->getAcceptsUserListChanges())
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
delete se; delete se;
clientsLock.unlock(); clientsLock.unlock();
ResponseContainer rc(-1); ResponseContainer rc(-1);
newUser->joinPersistentGames(rc); newUser->joinPersistentGames(rc);
newUser->sendResponseContainer(rc, Response::RespNothing); newUser->sendResponseContainer(rc, Response::RespNothing);
} }
void Server::externalUserLeft(const QString &userName) void Server::externalUserLeft(const QString &userName)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
clientsLock.lockForWrite(); clientsLock.lockForWrite();
Server_AbstractUserInterface *user = externalUsers.take(userName); Server_AbstractUserInterface *user = externalUsers.take(userName);
externalUsersBySessionId.remove(user->getUserInfo()->session_id()); externalUsersBySessionId.remove(user->getUserInfo()->session_id());
clientsLock.unlock(); clientsLock.unlock();
QMap<int, QPair<int, int> > userGames(user->getGames()); QMap<int, QPair<int, int> > userGames(user->getGames());
QMapIterator<int, QPair<int, int> > userGamesIterator(userGames); QMapIterator<int, QPair<int, int> > userGamesIterator(userGames);
roomsLock.lockForRead(); roomsLock.lockForRead();
while (userGamesIterator.hasNext()) { while (userGamesIterator.hasNext()) {
userGamesIterator.next(); userGamesIterator.next();
Server_Room *room = rooms.value(userGamesIterator.value().first); Server_Room *room = rooms.value(userGamesIterator.value().first);
if (!room) if (!room)
continue; continue;
QReadLocker roomGamesLocker(&room->gamesLock); QReadLocker roomGamesLocker(&room->gamesLock);
Server_Game *game = room->getGames().value(userGamesIterator.key()); Server_Game *game = room->getGames().value(userGamesIterator.key());
if (!game) if (!game)
continue; continue;
QMutexLocker gameLocker(&game->gameMutex); QMutexLocker gameLocker(&game->gameMutex);
Server_Player *player = game->getPlayers().value(userGamesIterator.value().second); Server_Player *player = game->getPlayers().value(userGamesIterator.value().second);
if (!player) if (!player)
continue; continue;
player->disconnectClient(); player->disconnectClient();
} }
roomsLock.unlock(); roomsLock.unlock();
delete user; delete user;
Event_UserLeft event; Event_UserLeft event;
event.set_name(userName.toStdString()); event.set_name(userName.toStdString());
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
clientsLock.lockForRead(); clientsLock.lockForRead();
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsUserListChanges()) if (clients[i]->getAcceptsUserListChanges())
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
clientsLock.unlock(); clientsLock.unlock();
delete se; delete se;
} }
void Server::externalRoomUserJoined(int roomId, const ServerInfo_User &userInfo) void Server::externalRoomUserJoined(int roomId, const ServerInfo_User &userInfo)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker locker(&roomsLock); QReadLocker locker(&roomsLock);
Server_Room *room = rooms.value(roomId); Server_Room *room = rooms.value(roomId);
if (!room) { if (!room) {
qDebug() << "externalRoomUserJoined: room id=" << roomId << "not found"; qDebug() << "externalRoomUserJoined: room id=" << roomId << "not found";
return; return;
} }
room->addExternalUser(userInfo); room->addExternalUser(userInfo);
} }
void Server::externalRoomUserLeft(int roomId, const QString &userName) void Server::externalRoomUserLeft(int roomId, const QString &userName)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker locker(&roomsLock); QReadLocker locker(&roomsLock);
Server_Room *room = rooms.value(roomId); Server_Room *room = rooms.value(roomId);
if (!room) { if (!room) {
qDebug() << "externalRoomUserLeft: room id=" << roomId << "not found"; qDebug() << "externalRoomUserLeft: room id=" << roomId << "not found";
return; return;
} }
room->removeExternalUser(userName); room->removeExternalUser(userName);
} }
void Server::externalRoomSay(int roomId, const QString &userName, const QString &message) void Server::externalRoomSay(int roomId, const QString &userName, const QString &message)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker locker(&roomsLock); QReadLocker locker(&roomsLock);
Server_Room *room = rooms.value(roomId); Server_Room *room = rooms.value(roomId);
if (!room) { if (!room) {
qDebug() << "externalRoomSay: room id=" << roomId << "not found"; qDebug() << "externalRoomSay: room id=" << roomId << "not found";
return; return;
} }
room->say(userName, message, false); room->say(userName, message, false);
} }
void Server::externalRoomGameListChanged(int roomId, const ServerInfo_Game &gameInfo) void Server::externalRoomGameListChanged(int roomId, const ServerInfo_Game &gameInfo)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker locker(&roomsLock); QReadLocker locker(&roomsLock);
Server_Room *room = rooms.value(roomId); Server_Room *room = rooms.value(roomId);
if (!room) { if (!room) {
qDebug() << "externalRoomGameListChanged: room id=" << roomId << "not found"; qDebug() << "externalRoomGameListChanged: room id=" << roomId << "not found";
return; return;
} }
room->updateExternalGameList(gameInfo); room->updateExternalGameList(gameInfo);
} }
void Server::externalJoinGameCommandReceived(const Command_JoinGame &cmd, int cmdId, int roomId, int serverId, qint64 sessionId) 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. // This function is always called from the main thread via signal/slot.
try { try {
QReadLocker roomsLocker(&roomsLock); QReadLocker roomsLocker(&roomsLock);
QReadLocker clientsLocker(&clientsLock); QReadLocker clientsLocker(&clientsLock);
Server_Room *room = rooms.value(roomId); Server_Room *room = rooms.value(roomId);
if (!room) { if (!room) {
qDebug() << "externalJoinGameCommandReceived: room id=" << roomId << "not found"; qDebug() << "externalJoinGameCommandReceived: room id=" << roomId << "not found";
throw Response::RespNotInRoom; throw Response::RespNotInRoom;
} }
Server_AbstractUserInterface *userInterface = externalUsersBySessionId.value(sessionId); Server_AbstractUserInterface *userInterface = externalUsersBySessionId.value(sessionId);
if (!userInterface) { if (!userInterface) {
qDebug() << "externalJoinGameCommandReceived: session id=" << sessionId << "not found"; qDebug() << "externalJoinGameCommandReceived: session id=" << sessionId << "not found";
throw Response::RespNotInRoom; throw Response::RespNotInRoom;
} }
ResponseContainer responseContainer(cmdId); ResponseContainer responseContainer(cmdId);
Response::ResponseCode responseCode = room->processJoinGameCommand(cmd, responseContainer, userInterface); Response::ResponseCode responseCode = room->processJoinGameCommand(cmd, responseContainer, userInterface);
userInterface->sendResponseContainer(responseContainer, responseCode); userInterface->sendResponseContainer(responseContainer, responseCode);
} catch (Response::ResponseCode code) { } catch (Response::ResponseCode code) {
Response response; Response response;
response.set_cmd_id(cmdId); response.set_cmd_id(cmdId);
response.set_response_code(code); response.set_response_code(code);
sendIsl_Response(response, serverId, sessionId); sendIsl_Response(response, serverId, sessionId);
} }
} }
void Server::externalGameCommandContainerReceived(const CommandContainer &cont, int playerId, int serverId, qint64 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. // This function is always called from the main thread via signal/slot.
try { try {
ResponseContainer responseContainer(cont.cmd_id()); ResponseContainer responseContainer(cont.cmd_id());
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
QReadLocker roomsLocker(&roomsLock); QReadLocker roomsLocker(&roomsLock);
Server_Room *room = rooms.value(cont.room_id()); Server_Room *room = rooms.value(cont.room_id());
if (!room) { if (!room) {
qDebug() << "externalGameCommandContainerReceived: room id=" << cont.room_id() << "not found"; qDebug() << "externalGameCommandContainerReceived: room id=" << cont.room_id() << "not found";
throw Response::RespNotInRoom; throw Response::RespNotInRoom;
} }
QReadLocker roomGamesLocker(&room->gamesLock); QReadLocker roomGamesLocker(&room->gamesLock);
Server_Game *game = room->getGames().value(cont.game_id()); Server_Game *game = room->getGames().value(cont.game_id());
if (!game) { if (!game) {
qDebug() << "externalGameCommandContainerReceived: game id=" << cont.game_id() << "not found"; qDebug() << "externalGameCommandContainerReceived: game id=" << cont.game_id() << "not found";
throw Response::RespNotInRoom; throw Response::RespNotInRoom;
} }
QMutexLocker gameLocker(&game->gameMutex); QMutexLocker gameLocker(&game->gameMutex);
Server_Player *player = game->getPlayers().value(playerId); Server_Player *player = game->getPlayers().value(playerId);
if (!player) { if (!player) {
qDebug() << "externalGameCommandContainerReceived: player id=" << playerId << "not found"; qDebug() << "externalGameCommandContainerReceived: player id=" << playerId << "not found";
throw Response::RespNotInRoom; throw Response::RespNotInRoom;
} }
GameEventStorage ges; GameEventStorage ges;
for (int i = cont.game_command_size() - 1; i >= 0; --i) { for (int i = cont.game_command_size() - 1; i >= 0; --i) {
const GameCommand &sc = cont.game_command(i); const GameCommand &sc = cont.game_command(i);
qDebug() << "[ISL]" << QString::fromStdString(sc.ShortDebugString()); qDebug() << "[ISL]" << QString::fromStdString(sc.ShortDebugString());
Response::ResponseCode resp = player->processGameCommand(sc, responseContainer, ges); Response::ResponseCode resp = player->processGameCommand(sc, responseContainer, ges);
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
ges.sendToGame(game); ges.sendToGame(game);
if (finalResponseCode != Response::RespNothing) { if (finalResponseCode != Response::RespNothing) {
player->playerMutex.lock(); player->playerMutex.lock();
player->getUserInterface()->sendResponseContainer(responseContainer, finalResponseCode); player->getUserInterface()->sendResponseContainer(responseContainer, finalResponseCode);
player->playerMutex.unlock(); player->playerMutex.unlock();
} }
} catch (Response::ResponseCode code) { } catch (Response::ResponseCode code) {
Response response; Response response;
response.set_cmd_id(cont.cmd_id()); response.set_cmd_id(cont.cmd_id());
response.set_response_code(code); response.set_response_code(code);
sendIsl_Response(response, serverId, sessionId); sendIsl_Response(response, serverId, sessionId);
} }
} }
void Server::externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId) void Server::externalGameEventContainerReceived(const GameEventContainer &cont, qint64 sessionId)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker usersLocker(&clientsLock); QReadLocker usersLocker(&clientsLock);
Server_ProtocolHandler *client = usersBySessionId.value(sessionId); Server_ProtocolHandler *client = usersBySessionId.value(sessionId);
if (!client) { if (!client) {
qDebug() << "externalGameEventContainerReceived: session" << sessionId << "not found"; qDebug() << "externalGameEventContainerReceived: session" << sessionId << "not found";
return; return;
} }
client->sendProtocolItem(cont); client->sendProtocolItem(cont);
} }
void Server::externalResponseReceived(const Response &resp, qint64 sessionId) void Server::externalResponseReceived(const Response &resp, qint64 sessionId)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
QReadLocker usersLocker(&clientsLock); QReadLocker usersLocker(&clientsLock);
Server_ProtocolHandler *client = usersBySessionId.value(sessionId); Server_ProtocolHandler *client = usersBySessionId.value(sessionId);
if (!client) { if (!client) {
qDebug() << "externalResponseReceived: session" << sessionId << "not found"; qDebug() << "externalResponseReceived: session" << sessionId << "not found";
return; return;
} }
client->sendProtocolItem(resp); client->sendProtocolItem(resp);
} }
void Server::broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl) void Server::broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl)
{ {
// This function is always called from the main thread via signal/slot. // This function is always called from the main thread via signal/slot.
Event_ListRooms event; Event_ListRooms event;
event.add_room_list()->CopyFrom(roomInfo); event.add_room_list()->CopyFrom(roomInfo);
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
clientsLock.lockForRead(); clientsLock.lockForRead();
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (clients[i]->getAcceptsRoomListChanges()) if (clients[i]->getAcceptsRoomListChanges())
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
clientsLock.unlock(); clientsLock.unlock();
if (sendToIsl) if (sendToIsl)
sendIsl_SessionEvent(*se); sendIsl_SessionEvent(*se);
delete se; delete se;
} }
void Server::addRoom(Server_Room *newRoom) void Server::addRoom(Server_Room *newRoom)
{ {
QWriteLocker locker(&roomsLock); QWriteLocker locker(&roomsLock);
qDebug() << "Adding room: ID=" << newRoom->getId() << "name=" << newRoom->getName(); qDebug() << "Adding room: ID=" << newRoom->getId() << "name=" << newRoom->getName();
rooms.insert(newRoom->getId(), newRoom); rooms.insert(newRoom->getId(), newRoom);
connect(newRoom, SIGNAL(roomInfoChanged(ServerInfo_Room)), this, SLOT(broadcastRoomUpdate(const ServerInfo_Room &)), Qt::QueuedConnection); connect(newRoom, SIGNAL(roomInfoChanged(ServerInfo_Room)), this, SLOT(broadcastRoomUpdate(const ServerInfo_Room &)), Qt::QueuedConnection);
} }
int Server::getUsersCount() const int Server::getUsersCount() const
{ {
QReadLocker locker(&clientsLock); QReadLocker locker(&clientsLock);
return users.size(); return users.size();
} }
int Server::getGamesCount() const int Server::getGamesCount() const
{ {
int result = 0; int result = 0;
QReadLocker locker(&roomsLock); QReadLocker locker(&roomsLock);
QMapIterator<int, Server_Room *> roomIterator(rooms); QMapIterator<int, Server_Room *> roomIterator(rooms);
while (roomIterator.hasNext()) { while (roomIterator.hasNext()) {
Server_Room *room = roomIterator.next().value(); Server_Room *room = roomIterator.next().value();
QReadLocker roomLocker(&room->gamesLock); QReadLocker roomLocker(&room->gamesLock);
result += room->getGames().size(); result += room->getGames().size();
} }
return result; return result;
} }
void Server::sendIsl_Response(const Response &item, int serverId, qint64 sessionId) void Server::sendIsl_Response(const Response &item, int serverId, qint64 sessionId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::RESPONSE); msg.set_message_type(IslMessage::RESPONSE);
if (sessionId != -1) if (sessionId != -1)
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
msg.mutable_response()->CopyFrom(item); msg.mutable_response()->CopyFrom(item);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }
void Server::sendIsl_SessionEvent(const SessionEvent &item, int serverId, qint64 sessionId) void Server::sendIsl_SessionEvent(const SessionEvent &item, int serverId, qint64 sessionId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::SESSION_EVENT); msg.set_message_type(IslMessage::SESSION_EVENT);
if (sessionId != -1) if (sessionId != -1)
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
msg.mutable_session_event()->CopyFrom(item); msg.mutable_session_event()->CopyFrom(item);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }
void Server::sendIsl_GameEventContainer(const GameEventContainer &item, int serverId, qint64 sessionId) void Server::sendIsl_GameEventContainer(const GameEventContainer &item, int serverId, qint64 sessionId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::GAME_EVENT_CONTAINER); msg.set_message_type(IslMessage::GAME_EVENT_CONTAINER);
if (sessionId != -1) if (sessionId != -1)
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
msg.mutable_game_event_container()->CopyFrom(item); msg.mutable_game_event_container()->CopyFrom(item);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }
void Server::sendIsl_RoomEvent(const RoomEvent &item, int serverId, qint64 sessionId) void Server::sendIsl_RoomEvent(const RoomEvent &item, int serverId, qint64 sessionId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::ROOM_EVENT); msg.set_message_type(IslMessage::ROOM_EVENT);
if (sessionId != -1) if (sessionId != -1)
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
msg.mutable_room_event()->CopyFrom(item); msg.mutable_room_event()->CopyFrom(item);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }
void Server::sendIsl_GameCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId, int playerId) void Server::sendIsl_GameCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId, int playerId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::GAME_COMMAND_CONTAINER); msg.set_message_type(IslMessage::GAME_COMMAND_CONTAINER);
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
msg.set_player_id(playerId); msg.set_player_id(playerId);
CommandContainer *cont = msg.mutable_game_command(); CommandContainer *cont = msg.mutable_game_command();
cont->CopyFrom(item); cont->CopyFrom(item);
cont->set_room_id(roomId); cont->set_room_id(roomId);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }
void Server::sendIsl_RoomCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId) void Server::sendIsl_RoomCommand(const CommandContainer &item, int serverId, qint64 sessionId, int roomId)
{ {
IslMessage msg; IslMessage msg;
msg.set_message_type(IslMessage::ROOM_COMMAND_CONTAINER); msg.set_message_type(IslMessage::ROOM_COMMAND_CONTAINER);
msg.set_session_id(sessionId); msg.set_session_id(sessionId);
CommandContainer *cont = msg.mutable_room_command(); CommandContainer *cont = msg.mutable_room_command();
cont->CopyFrom(item); cont->CopyFrom(item);
cont->set_room_id(roomId); cont->set_room_id(roomId);
emit sigSendIslMessage(msg, serverId); emit sigSendIslMessage(msg, serverId);
} }

View file

@ -21,17 +21,17 @@
#include <google/protobuf/descriptor.h> #include <google/protobuf/descriptor.h>
Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, QObject *parent) Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, QObject *parent)
: QObject(parent), : QObject(parent),
Server_AbstractUserInterface(_server), Server_AbstractUserInterface(_server),
deleted(false), deleted(false),
databaseInterface(_databaseInterface), databaseInterface(_databaseInterface),
authState(NotLoggedIn), authState(NotLoggedIn),
acceptsUserListChanges(false), acceptsUserListChanges(false),
acceptsRoomListChanges(false), acceptsRoomListChanges(false),
timeRunning(0), timeRunning(0),
lastDataReceived(0) lastDataReceived(0)
{ {
connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout())); connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout()));
} }
Server_ProtocolHandler::~Server_ProtocolHandler() 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). // The thread must not hold any server locks when calling this (e.g. clientsLock, roomsLock).
void Server_ProtocolHandler::prepareDestroy() void Server_ProtocolHandler::prepareDestroy()
{ {
if (deleted) if (deleted)
return; return;
deleted = true; deleted = true;
QMapIterator<int, Server_Room *> roomIterator(rooms); QMapIterator<int, Server_Room *> roomIterator(rooms);
while (roomIterator.hasNext()) while (roomIterator.hasNext())
roomIterator.next().value()->removeClient(this); roomIterator.next().value()->removeClient(this);
QMap<int, QPair<int, int> > tempGames(getGames()); QMap<int, QPair<int, int> > tempGames(getGames());
server->roomsLock.lockForRead(); server->roomsLock.lockForRead();
QMapIterator<int, QPair<int, int> > gameIterator(tempGames); QMapIterator<int, QPair<int, int> > gameIterator(tempGames);
while (gameIterator.hasNext()) { while (gameIterator.hasNext()) {
gameIterator.next(); gameIterator.next();
Server_Room *r = server->getRooms().value(gameIterator.value().first); Server_Room *r = server->getRooms().value(gameIterator.value().first);
if (!r) if (!r)
continue; continue;
r->gamesLock.lockForRead(); r->gamesLock.lockForRead();
Server_Game *g = r->getGames().value(gameIterator.key()); Server_Game *g = r->getGames().value(gameIterator.key());
if (!g) { if (!g) {
r->gamesLock.unlock(); r->gamesLock.unlock();
continue; continue;
} }
g->gameMutex.lock(); g->gameMutex.lock();
Server_Player *p = g->getPlayers().value(gameIterator.value().second); Server_Player *p = g->getPlayers().value(gameIterator.value().second);
if (!p) { if (!p) {
g->gameMutex.unlock(); g->gameMutex.unlock();
r->gamesLock.unlock(); r->gamesLock.unlock();
continue; continue;
} }
p->disconnectClient(); p->disconnectClient();
g->gameMutex.unlock(); g->gameMutex.unlock();
r->gamesLock.unlock(); r->gamesLock.unlock();
} }
server->roomsLock.unlock(); server->roomsLock.unlock();
server->removeClient(this); server->removeClient(this);
deleteLater(); deleteLater();
} }
void Server_ProtocolHandler::sendProtocolItem(const Response &item) void Server_ProtocolHandler::sendProtocolItem(const Response &item)
{ {
ServerMessage msg; ServerMessage msg;
msg.mutable_response()->CopyFrom(item); msg.mutable_response()->CopyFrom(item);
msg.set_message_type(ServerMessage::RESPONSE); msg.set_message_type(ServerMessage::RESPONSE);
transmitProtocolItem(msg); transmitProtocolItem(msg);
} }
void Server_ProtocolHandler::sendProtocolItem(const SessionEvent &item) void Server_ProtocolHandler::sendProtocolItem(const SessionEvent &item)
{ {
ServerMessage msg; ServerMessage msg;
msg.mutable_session_event()->CopyFrom(item); msg.mutable_session_event()->CopyFrom(item);
msg.set_message_type(ServerMessage::SESSION_EVENT); msg.set_message_type(ServerMessage::SESSION_EVENT);
transmitProtocolItem(msg); transmitProtocolItem(msg);
} }
void Server_ProtocolHandler::sendProtocolItem(const GameEventContainer &item) void Server_ProtocolHandler::sendProtocolItem(const GameEventContainer &item)
{ {
ServerMessage msg; ServerMessage msg;
msg.mutable_game_event_container()->CopyFrom(item); msg.mutable_game_event_container()->CopyFrom(item);
msg.set_message_type(ServerMessage::GAME_EVENT_CONTAINER); msg.set_message_type(ServerMessage::GAME_EVENT_CONTAINER);
transmitProtocolItem(msg); transmitProtocolItem(msg);
} }
void Server_ProtocolHandler::sendProtocolItem(const RoomEvent &item) void Server_ProtocolHandler::sendProtocolItem(const RoomEvent &item)
{ {
ServerMessage msg; ServerMessage msg;
msg.mutable_room_event()->CopyFrom(item); msg.mutable_room_event()->CopyFrom(item);
msg.set_message_type(ServerMessage::ROOM_EVENT); msg.set_message_type(ServerMessage::ROOM_EVENT);
transmitProtocolItem(msg); transmitProtocolItem(msg);
} }
Response::ResponseCode Server_ProtocolHandler::processSessionCommandContainer(const CommandContainer &cont, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::processSessionCommandContainer(const CommandContainer &cont, ResponseContainer &rc)
{ {
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.session_command_size() - 1; i >= 0; --i) { for (int i = cont.session_command_size() - 1; i >= 0; --i) {
Response::ResponseCode resp = Response::RespInvalidCommand; Response::ResponseCode resp = Response::RespInvalidCommand;
const SessionCommand &sc = cont.session_command(i); const SessionCommand &sc = cont.session_command(i);
const int num = getPbExtension(sc); const int num = getPbExtension(sc);
if (num != SessionCommand::PING) { // don't log ping commands if (num != SessionCommand::PING) { // don't log ping commands
if (num == SessionCommand::LOGIN) { // log login commands, but hide passwords if (num == SessionCommand::LOGIN) { // log login commands, but hide passwords
SessionCommand debugSc(sc); SessionCommand debugSc(sc);
debugSc.MutableExtension(Command_Login::ext)->clear_password(); debugSc.MutableExtension(Command_Login::ext)->clear_password();
logDebugMessage(QString::fromStdString(debugSc.ShortDebugString())); logDebugMessage(QString::fromStdString(debugSc.ShortDebugString()));
} else } else
logDebugMessage(QString::fromStdString(sc.ShortDebugString())); logDebugMessage(QString::fromStdString(sc.ShortDebugString()));
} }
switch ((SessionCommand::SessionCommandType) num) { switch ((SessionCommand::SessionCommandType) num) {
case SessionCommand::PING: resp = cmdPing(sc.GetExtension(Command_Ping::ext), rc); break; 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::LOGIN: resp = cmdLogin(sc.GetExtension(Command_Login::ext), rc); break;
case SessionCommand::MESSAGE: resp = cmdMessage(sc.GetExtension(Command_Message::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_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::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::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::JOIN_ROOM: resp = cmdJoinRoom(sc.GetExtension(Command_JoinRoom::ext), rc); break;
case SessionCommand::LIST_USERS: resp = cmdListUsers(sc.GetExtension(Command_ListUsers::ext), rc); break; case SessionCommand::LIST_USERS: resp = cmdListUsers(sc.GetExtension(Command_ListUsers::ext), rc); break;
default: resp = processExtendedSessionCommand(num, sc, rc); default: resp = processExtendedSessionCommand(num, sc, rc);
} }
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
return finalResponseCode; return finalResponseCode;
} }
Response::ResponseCode Server_ProtocolHandler::processRoomCommandContainer(const CommandContainer &cont, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::processRoomCommandContainer(const CommandContainer &cont, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
QReadLocker locker(&server->roomsLock); QReadLocker locker(&server->roomsLock);
Server_Room *room = rooms.value(cont.room_id(), 0); Server_Room *room = rooms.value(cont.room_id(), 0);
if (!room) if (!room)
return Response::RespNotInRoom; return Response::RespNotInRoom;
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.room_command_size() - 1; i >= 0; --i) { for (int i = cont.room_command_size() - 1; i >= 0; --i) {
Response::ResponseCode resp = Response::RespInvalidCommand; Response::ResponseCode resp = Response::RespInvalidCommand;
const RoomCommand &sc = cont.room_command(i); const RoomCommand &sc = cont.room_command(i);
const int num = getPbExtension(sc); const int num = getPbExtension(sc);
logDebugMessage(QString::fromStdString(sc.ShortDebugString())); logDebugMessage(QString::fromStdString(sc.ShortDebugString()));
switch ((RoomCommand::RoomCommandType) num) { switch ((RoomCommand::RoomCommandType) num) {
case RoomCommand::LEAVE_ROOM: resp = cmdLeaveRoom(sc.GetExtension(Command_LeaveRoom::ext), room, rc); break; 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::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::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; case RoomCommand::JOIN_GAME: resp = cmdJoinGame(sc.GetExtension(Command_JoinGame::ext), room, rc); break;
} }
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
return finalResponseCode; return finalResponseCode;
} }
Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::processGameCommandContainer(const CommandContainer &cont, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
QMap<int, QPair<int, int> > gameMap = getGames(); QMap<int, QPair<int, int> > gameMap = getGames();
if (!gameMap.contains(cont.game_id())) if (!gameMap.contains(cont.game_id()))
return Response::RespNotInRoom; return Response::RespNotInRoom;
const QPair<int, int> roomIdAndPlayerId = gameMap.value(cont.game_id()); const QPair<int, int> roomIdAndPlayerId = gameMap.value(cont.game_id());
QReadLocker roomsLocker(&server->roomsLock); QReadLocker roomsLocker(&server->roomsLock);
Server_Room *room = server->getRooms().value(roomIdAndPlayerId.first); Server_Room *room = server->getRooms().value(roomIdAndPlayerId.first);
if (!room) if (!room)
return Response::RespNotInRoom; return Response::RespNotInRoom;
QReadLocker roomGamesLocker(&room->gamesLock); QReadLocker roomGamesLocker(&room->gamesLock);
Server_Game *game = room->getGames().value(cont.game_id()); Server_Game *game = room->getGames().value(cont.game_id());
if (!game) { if (!game) {
if (room->getExternalGames().contains(cont.game_id())) { if (room->getExternalGames().contains(cont.game_id())) {
server->sendIsl_GameCommand(cont, server->sendIsl_GameCommand(cont,
room->getExternalGames().value(cont.game_id()).server_id(), room->getExternalGames().value(cont.game_id()).server_id(),
userInfo->session_id(), userInfo->session_id(),
roomIdAndPlayerId.first, roomIdAndPlayerId.first,
roomIdAndPlayerId.second roomIdAndPlayerId.second
); );
return Response::RespNothing; return Response::RespNothing;
} }
return Response::RespNotInRoom; return Response::RespNotInRoom;
} }
QMutexLocker gameLocker(&game->gameMutex); QMutexLocker gameLocker(&game->gameMutex);
Server_Player *player = game->getPlayers().value(roomIdAndPlayerId.second); Server_Player *player = game->getPlayers().value(roomIdAndPlayerId.second);
if (!player) if (!player)
return Response::RespNotInRoom; return Response::RespNotInRoom;
GameEventStorage ges; GameEventStorage ges;
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.game_command_size() - 1; i >= 0; --i) { for (int i = cont.game_command_size() - 1; i >= 0; --i) {
const GameCommand &sc = cont.game_command(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())); 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); Response::ResponseCode resp = player->processGameCommand(sc, rc, ges);
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
ges.sendToGame(game); ges.sendToGame(game);
return finalResponseCode; return finalResponseCode;
} }
Response::ResponseCode Server_ProtocolHandler::processModeratorCommandContainer(const CommandContainer &cont, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::processModeratorCommandContainer(const CommandContainer &cont, ResponseContainer &rc)
{ {
if (!userInfo) if (!userInfo)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
if (!(userInfo->user_level() & ServerInfo_User::IsModerator)) if (!(userInfo->user_level() & ServerInfo_User::IsModerator))
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.moderator_command_size() - 1; i >= 0; --i) { for (int i = cont.moderator_command_size() - 1; i >= 0; --i) {
Response::ResponseCode resp = Response::RespInvalidCommand; Response::ResponseCode resp = Response::RespInvalidCommand;
const ModeratorCommand &sc = cont.moderator_command(i); const ModeratorCommand &sc = cont.moderator_command(i);
const int num = getPbExtension(sc); const int num = getPbExtension(sc);
logDebugMessage(QString::fromStdString(sc.ShortDebugString())); logDebugMessage(QString::fromStdString(sc.ShortDebugString()));
resp = processExtendedModeratorCommand(num, sc, rc); resp = processExtendedModeratorCommand(num, sc, rc);
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
return finalResponseCode; return finalResponseCode;
} }
Response::ResponseCode Server_ProtocolHandler::processAdminCommandContainer(const CommandContainer &cont, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::processAdminCommandContainer(const CommandContainer &cont, ResponseContainer &rc)
{ {
if (!userInfo) if (!userInfo)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
if (!(userInfo->user_level() & ServerInfo_User::IsAdmin)) if (!(userInfo->user_level() & ServerInfo_User::IsAdmin))
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
Response::ResponseCode finalResponseCode = Response::RespOk; Response::ResponseCode finalResponseCode = Response::RespOk;
for (int i = cont.admin_command_size() - 1; i >= 0; --i) { for (int i = cont.admin_command_size() - 1; i >= 0; --i) {
Response::ResponseCode resp = Response::RespInvalidCommand; Response::ResponseCode resp = Response::RespInvalidCommand;
const AdminCommand &sc = cont.admin_command(i); const AdminCommand &sc = cont.admin_command(i);
const int num = getPbExtension(sc); const int num = getPbExtension(sc);
logDebugMessage(QString::fromStdString(sc.ShortDebugString())); logDebugMessage(QString::fromStdString(sc.ShortDebugString()));
resp = processExtendedAdminCommand(num, sc, rc); resp = processExtendedAdminCommand(num, sc, rc);
if (resp != Response::RespOk) if (resp != Response::RespOk)
finalResponseCode = resp; finalResponseCode = resp;
} }
return finalResponseCode; return finalResponseCode;
} }
void Server_ProtocolHandler::processCommandContainer(const CommandContainer &cont) void Server_ProtocolHandler::processCommandContainer(const CommandContainer &cont)
{ {
// Command processing must be disabled after prepareDestroy() has been called. // Command processing must be disabled after prepareDestroy() has been called.
if (deleted) if (deleted)
return; return;
lastDataReceived = timeRunning; lastDataReceived = timeRunning;
ResponseContainer responseContainer(cont.has_cmd_id() ? cont.cmd_id() : -1); ResponseContainer responseContainer(cont.has_cmd_id() ? cont.cmd_id() : -1);
Response::ResponseCode finalResponseCode; Response::ResponseCode finalResponseCode;
if (cont.game_command_size()) if (cont.game_command_size())
finalResponseCode = processGameCommandContainer(cont, responseContainer); finalResponseCode = processGameCommandContainer(cont, responseContainer);
else if (cont.room_command_size()) else if (cont.room_command_size())
finalResponseCode = processRoomCommandContainer(cont, responseContainer); finalResponseCode = processRoomCommandContainer(cont, responseContainer);
else if (cont.session_command_size()) else if (cont.session_command_size())
finalResponseCode = processSessionCommandContainer(cont, responseContainer); finalResponseCode = processSessionCommandContainer(cont, responseContainer);
else if (cont.moderator_command_size()) else if (cont.moderator_command_size())
finalResponseCode = processModeratorCommandContainer(cont, responseContainer); finalResponseCode = processModeratorCommandContainer(cont, responseContainer);
else if (cont.admin_command_size()) else if (cont.admin_command_size())
finalResponseCode = processAdminCommandContainer(cont, responseContainer); finalResponseCode = processAdminCommandContainer(cont, responseContainer);
else else
finalResponseCode = Response::RespInvalidCommand; finalResponseCode = Response::RespInvalidCommand;
if ((finalResponseCode != Response::RespNothing)) if ((finalResponseCode != Response::RespNothing))
sendResponseContainer(responseContainer, finalResponseCode); sendResponseContainer(responseContainer, finalResponseCode);
} }
void Server_ProtocolHandler::pingClockTimeout() void Server_ProtocolHandler::pingClockTimeout()
{ {
int interval = server->getMessageCountingInterval(); int interval = server->getMessageCountingInterval();
if (interval > 0) { if (interval > 0) {
messageSizeOverTime.prepend(0); messageSizeOverTime.prepend(0);
if (messageSizeOverTime.size() > server->getMessageCountingInterval()) if (messageSizeOverTime.size() > server->getMessageCountingInterval())
messageSizeOverTime.removeLast(); messageSizeOverTime.removeLast();
messageCountOverTime.prepend(0); messageCountOverTime.prepend(0);
if (messageCountOverTime.size() > server->getMessageCountingInterval()) if (messageCountOverTime.size() > server->getMessageCountingInterval())
messageCountOverTime.removeLast(); messageCountOverTime.removeLast();
} }
if (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime()) if (timeRunning - lastDataReceived > server->getMaxPlayerInactivityTime())
prepareDestroy(); prepareDestroy();
++timeRunning; ++timeRunning;
} }
Response::ResponseCode Server_ProtocolHandler::cmdPing(const Command_Ping & /*cmd*/, ResponseContainer & /*rc*/) 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) Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd, ResponseContainer &rc)
{ {
QString userName = QString::fromStdString(cmd.user_name()).simplified(); QString userName = QString::fromStdString(cmd.user_name()).simplified();
if (userName.isEmpty() || (userInfo != 0)) if (userName.isEmpty() || (userInfo != 0))
return Response::RespContextError; return Response::RespContextError;
QString reasonStr; QString reasonStr;
int banSecondsLeft = 0; int banSecondsLeft = 0;
AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft); AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft);
switch (res) { switch (res) {
case UserIsBanned: { case UserIsBanned: {
Response_Login *re = new Response_Login; Response_Login *re = new Response_Login;
re->set_denied_reason_str(reasonStr.toStdString()); re->set_denied_reason_str(reasonStr.toStdString());
if (banSecondsLeft != 0) if (banSecondsLeft != 0)
re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsLeft).toTime_t()); re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsLeft).toTime_t());
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespUserIsBanned; return Response::RespUserIsBanned;
} }
case NotLoggedIn: return Response::RespWrongPassword; case NotLoggedIn: return Response::RespWrongPassword;
case WouldOverwriteOldSession: return Response::RespWouldOverwriteOldSession; case WouldOverwriteOldSession: return Response::RespWouldOverwriteOldSession;
case UsernameInvalid: return Response::RespUsernameInvalid; case UsernameInvalid: return Response::RespUsernameInvalid;
case RegistrationRequired: return Response::RespRegistrationRequired; case RegistrationRequired: return Response::RespRegistrationRequired;
default: authState = res; default: authState = res;
} }
userName = QString::fromStdString(userInfo->name()); userName = QString::fromStdString(userInfo->name());
Event_ServerMessage event; Event_ServerMessage event;
event.set_message(server->getLoginMessage().toStdString()); event.set_message(server->getLoginMessage().toStdString());
rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event)); rc.enqueuePostResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event));
Response_Login *re = new Response_Login; Response_Login *re = new Response_Login;
re->mutable_user_info()->CopyFrom(copyUserInfo(true)); re->mutable_user_info()->CopyFrom(copyUserInfo(true));
if (authState == PasswordRight) { if (authState == PasswordRight) {
QMapIterator<QString, ServerInfo_User> buddyIterator(databaseInterface->getBuddyList(userName)); QMapIterator<QString, ServerInfo_User> buddyIterator(databaseInterface->getBuddyList(userName));
while (buddyIterator.hasNext()) while (buddyIterator.hasNext())
re->add_buddy_list()->CopyFrom(buddyIterator.next().value()); re->add_buddy_list()->CopyFrom(buddyIterator.next().value());
QMapIterator<QString, ServerInfo_User> ignoreIterator(databaseInterface->getIgnoreList(userName)); QMapIterator<QString, ServerInfo_User> ignoreIterator(databaseInterface->getIgnoreList(userName));
while (ignoreIterator.hasNext()) while (ignoreIterator.hasNext())
re->add_ignore_list()->CopyFrom(ignoreIterator.next().value()); re->add_ignore_list()->CopyFrom(ignoreIterator.next().value());
} }
joinPersistentGames(rc); joinPersistentGames(rc);
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdMessage(const Command_Message &cmd, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdMessage(const Command_Message &cmd, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
QReadLocker locker(&server->clientsLock); QReadLocker locker(&server->clientsLock);
QString receiver = QString::fromStdString(cmd.user_name()); QString receiver = QString::fromStdString(cmd.user_name());
Server_AbstractUserInterface *userInterface = server->findUser(receiver); Server_AbstractUserInterface *userInterface = server->findUser(receiver);
if (!userInterface) if (!userInterface)
return Response::RespNameNotFound; return Response::RespNameNotFound;
if (databaseInterface->isInIgnoreList(receiver, QString::fromStdString(userInfo->name()))) if (databaseInterface->isInIgnoreList(receiver, QString::fromStdString(userInfo->name())))
return Response::RespInIgnoreList; return Response::RespInIgnoreList;
Event_UserMessage event; Event_UserMessage event;
event.set_sender_name(userInfo->name()); event.set_sender_name(userInfo->name());
event.set_receiver_name(cmd.user_name()); event.set_receiver_name(cmd.user_name());
event.set_message(cmd.message()); event.set_message(cmd.message());
SessionEvent *se = prepareSessionEvent(event); SessionEvent *se = prepareSessionEvent(event);
userInterface->sendProtocolItem(*se); userInterface->sendProtocolItem(*se);
rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, se); rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, se);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdGetGamesOfUser(const Command_GetGamesOfUser &cmd, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdGetGamesOfUser(const Command_GetGamesOfUser &cmd, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
// We don't need to check whether the user is logged in; persistent games should also work. // 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. // The client needs to deal with an empty result list.
Response_GetGamesOfUser *re = new Response_GetGamesOfUser; Response_GetGamesOfUser *re = new Response_GetGamesOfUser;
server->roomsLock.lockForRead(); server->roomsLock.lockForRead();
QMapIterator<int, Server_Room *> roomIterator(server->getRooms()); QMapIterator<int, Server_Room *> roomIterator(server->getRooms());
while (roomIterator.hasNext()) { while (roomIterator.hasNext()) {
Server_Room *room = roomIterator.next().value(); Server_Room *room = roomIterator.next().value();
room->gamesLock.lockForRead(); room->gamesLock.lockForRead();
room->getInfo(*re->add_room_list(), false, true); room->getInfo(*re->add_room_list(), false, true);
QListIterator<ServerInfo_Game> gameIterator(room->getGamesOfUser(QString::fromStdString(cmd.user_name()))); QListIterator<ServerInfo_Game> gameIterator(room->getGamesOfUser(QString::fromStdString(cmd.user_name())));
while (gameIterator.hasNext()) while (gameIterator.hasNext())
re->add_game_list()->CopyFrom(gameIterator.next()); re->add_game_list()->CopyFrom(gameIterator.next());
room->gamesLock.unlock(); room->gamesLock.unlock();
} }
server->roomsLock.unlock(); server->roomsLock.unlock();
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdGetUserInfo(const Command_GetUserInfo &cmd, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdGetUserInfo(const Command_GetUserInfo &cmd, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
QString userName = QString::fromStdString(cmd.user_name()); QString userName = QString::fromStdString(cmd.user_name());
Response_GetUserInfo *re = new Response_GetUserInfo; Response_GetUserInfo *re = new Response_GetUserInfo;
if (userName.isEmpty()) if (userName.isEmpty())
re->mutable_user_info()->CopyFrom(*userInfo); re->mutable_user_info()->CopyFrom(*userInfo);
else { else {
QReadLocker locker(&server->clientsLock); QReadLocker locker(&server->clientsLock);
ServerInfo_User_Container *infoSource = server->findUser(userName); ServerInfo_User_Container *infoSource = server->findUser(userName);
if (!infoSource) if (!infoSource)
return Response::RespNameNotFound; return Response::RespNameNotFound;
re->mutable_user_info()->CopyFrom(infoSource->copyUserInfo(true, false, userInfo->user_level() & ServerInfo_User::IsModerator)); re->mutable_user_info()->CopyFrom(infoSource->copyUserInfo(true, false, userInfo->user_level() & ServerInfo_User::IsModerator));
} }
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdListRooms(const Command_ListRooms & /*cmd*/, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdListRooms(const Command_ListRooms & /*cmd*/, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
Event_ListRooms event; Event_ListRooms event;
QMapIterator<int, Server_Room *> roomIterator(server->getRooms()); QMapIterator<int, Server_Room *> roomIterator(server->getRooms());
while (roomIterator.hasNext()) while (roomIterator.hasNext())
roomIterator.next().value()->getInfo(*event.add_room_list(), false); roomIterator.next().value()->getInfo(*event.add_room_list(), false);
rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event)); rc.enqueuePreResponseItem(ServerMessage::SESSION_EVENT, prepareSessionEvent(event));
acceptsRoomListChanges = true; acceptsRoomListChanges = true;
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdJoinRoom(const Command_JoinRoom &cmd, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdJoinRoom(const Command_JoinRoom &cmd, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
if (rooms.contains(cmd.room_id())) if (rooms.contains(cmd.room_id()))
return Response::RespContextError; return Response::RespContextError;
QReadLocker serverLocker(&server->roomsLock); QReadLocker serverLocker(&server->roomsLock);
Server_Room *r = server->getRooms().value(cmd.room_id(), 0); Server_Room *r = server->getRooms().value(cmd.room_id(), 0);
if (!r) if (!r)
return Response::RespNameNotFound; return Response::RespNameNotFound;
r->addClient(this); r->addClient(this);
rooms.insert(r->getId(), r); rooms.insert(r->getId(), r);
Event_RoomSay joinMessageEvent; Event_RoomSay joinMessageEvent;
joinMessageEvent.set_message(r->getJoinMessage().toStdString()); joinMessageEvent.set_message(r->getJoinMessage().toStdString());
rc.enqueuePostResponseItem(ServerMessage::ROOM_EVENT, r->prepareRoomEvent(joinMessageEvent)); rc.enqueuePostResponseItem(ServerMessage::ROOM_EVENT, r->prepareRoomEvent(joinMessageEvent));
Response_JoinRoom *re = new Response_JoinRoom; Response_JoinRoom *re = new Response_JoinRoom;
r->getInfo(*re->mutable_room_info(), true); r->getInfo(*re->mutable_room_info(), true);
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUsers & /*cmd*/, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUsers & /*cmd*/, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
Response_ListUsers *re = new Response_ListUsers; Response_ListUsers *re = new Response_ListUsers;
server->clientsLock.lockForRead(); server->clientsLock.lockForRead();
QMapIterator<QString, Server_ProtocolHandler *> userIterator = server->getUsers(); QMapIterator<QString, Server_ProtocolHandler *> userIterator = server->getUsers();
while (userIterator.hasNext()) while (userIterator.hasNext())
re->add_user_list()->CopyFrom(userIterator.next().value()->copyUserInfo(false)); re->add_user_list()->CopyFrom(userIterator.next().value()->copyUserInfo(false));
QMapIterator<QString, Server_AbstractUserInterface *> extIterator = server->getExternalUsers(); QMapIterator<QString, Server_AbstractUserInterface *> extIterator = server->getExternalUsers();
while (extIterator.hasNext()) while (extIterator.hasNext())
re->add_user_list()->CopyFrom(extIterator.next().value()->copyUserInfo(false)); re->add_user_list()->CopyFrom(extIterator.next().value()->copyUserInfo(false));
acceptsUserListChanges = true; acceptsUserListChanges = true;
server->clientsLock.unlock(); server->clientsLock.unlock();
rc.setResponseExtension(re); rc.setResponseExtension(re);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdLeaveRoom(const Command_LeaveRoom & /*cmd*/, Server_Room *room, ResponseContainer & /*rc*/) Response::ResponseCode Server_ProtocolHandler::cmdLeaveRoom(const Command_LeaveRoom & /*cmd*/, Server_Room *room, ResponseContainer & /*rc*/)
{ {
rooms.remove(room->getId()); rooms.remove(room->getId());
room->removeClient(this); room->removeClient(this);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdRoomSay(const Command_RoomSay &cmd, Server_Room *room, ResponseContainer & /*rc*/) Response::ResponseCode Server_ProtocolHandler::cmdRoomSay(const Command_RoomSay &cmd, Server_Room *room, ResponseContainer & /*rc*/)
{ {
QString msg = QString::fromStdString(cmd.message()); QString msg = QString::fromStdString(cmd.message());
if (server->getMessageCountingInterval() > 0) { if (server->getMessageCountingInterval() > 0) {
int totalSize = 0, totalCount = 0; int totalSize = 0, totalCount = 0;
if (messageSizeOverTime.isEmpty()) if (messageSizeOverTime.isEmpty())
messageSizeOverTime.prepend(0); messageSizeOverTime.prepend(0);
messageSizeOverTime[0] += msg.size(); messageSizeOverTime[0] += msg.size();
for (int i = 0; i < messageSizeOverTime.size(); ++i) for (int i = 0; i < messageSizeOverTime.size(); ++i)
totalSize += messageSizeOverTime[i]; totalSize += messageSizeOverTime[i];
if (messageCountOverTime.isEmpty()) if (messageCountOverTime.isEmpty())
messageCountOverTime.prepend(0); messageCountOverTime.prepend(0);
++messageCountOverTime[0]; ++messageCountOverTime[0];
for (int i = 0; i < messageCountOverTime.size(); ++i) for (int i = 0; i < messageCountOverTime.size(); ++i)
totalCount += messageCountOverTime[i]; totalCount += messageCountOverTime[i];
if ((totalSize > server->getMaxMessageSizePerInterval()) || (totalCount > server->getMaxMessageCountPerInterval())) if ((totalSize > server->getMaxMessageSizePerInterval()) || (totalCount > server->getMaxMessageCountPerInterval()))
return Response::RespChatFlood; return Response::RespChatFlood;
} }
msg.replace(QChar('\n'), QChar(' ')); msg.replace(QChar('\n'), QChar(' '));
room->say(QString::fromStdString(userInfo->name()), msg); room->say(QString::fromStdString(userInfo->name()), msg);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room *room, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdCreateGame(const Command_CreateGame &cmd, Server_Room *room, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
const int gameId = databaseInterface->getNextGameId(); const int gameId = databaseInterface->getNextGameId();
if (gameId == -1) if (gameId == -1)
return Response::RespInternalError; return Response::RespInternalError;
if (server->getMaxGamesPerUser() > 0) if (server->getMaxGamesPerUser() > 0)
if (room->getGamesCreatedByUser(QString::fromStdString(userInfo->name())) >= server->getMaxGamesPerUser()) if (room->getGamesCreatedByUser(QString::fromStdString(userInfo->name())) >= server->getMaxGamesPerUser())
return Response::RespContextError; return Response::RespContextError;
QList<int> gameTypes; QList<int> gameTypes;
for (int i = cmd.game_type_ids_size() - 1; i >= 0; --i) for (int i = cmd.game_type_ids_size() - 1; i >= 0; --i)
gameTypes.append(cmd.game_type_ids(i)); gameTypes.append(cmd.game_type_ids(i));
QString description = QString::fromStdString(cmd.description()); QString description = QString::fromStdString(cmd.description());
if (description.size() > 60) if (description.size() > 60)
description = description.left(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); 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); game->addPlayer(this, rc, false, false);
room->addGame(game); room->addGame(game);
return Response::RespOk; return Response::RespOk;
} }
Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGame &cmd, Server_Room *room, ResponseContainer &rc) Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGame &cmd, Server_Room *room, ResponseContainer &rc)
{ {
if (authState == NotLoggedIn) if (authState == NotLoggedIn)
return Response::RespLoginNeeded; return Response::RespLoginNeeded;
return room->processJoinGameCommand(cmd, rc, this); return room->processJoinGameCommand(cmd, rc, this);
} }

View file

@ -7,7 +7,6 @@ id=1
number_pools=1 number_pools=1
writelog=1 writelog=1
logfilters="" logfilters=""
regonly=0
[servernetwork] [servernetwork]
active=0 active=0
@ -17,6 +16,7 @@ ssl_key=ssl_key.pem
[authentication] [authentication]
method=none method=none
regonly=0
[database] [database]
type=none type=none

View file

@ -38,481 +38,481 @@
#include "pb/event_connection_closed.pb.h" #include "pb/event_connection_closed.pb.h"
Servatrice_GameServer::Servatrice_GameServer(Servatrice *_server, int _numberPools, const QSqlDatabase &_sqlDatabase, QObject *parent) Servatrice_GameServer::Servatrice_GameServer(Servatrice *_server, int _numberPools, const QSqlDatabase &_sqlDatabase, QObject *parent)
: QTcpServer(parent), : QTcpServer(parent),
server(_server) server(_server)
{ {
if (_numberPools == 0) { if (_numberPools == 0) {
server->setThreaded(false); server->setThreaded(false);
Servatrice_DatabaseInterface *newDatabaseInterface = new Servatrice_DatabaseInterface(0, server); Servatrice_DatabaseInterface *newDatabaseInterface = new Servatrice_DatabaseInterface(0, server);
Servatrice_ConnectionPool *newPool = new Servatrice_ConnectionPool(newDatabaseInterface); Servatrice_ConnectionPool *newPool = new Servatrice_ConnectionPool(newDatabaseInterface);
server->addDatabaseInterface(thread(), newDatabaseInterface); server->addDatabaseInterface(thread(), newDatabaseInterface);
newDatabaseInterface->initDatabase(_sqlDatabase); newDatabaseInterface->initDatabase(_sqlDatabase);
connectionPools.append(newPool); connectionPools.append(newPool);
} else } else
for (int i = 0; i < _numberPools; ++i) { for (int i = 0; i < _numberPools; ++i) {
Servatrice_DatabaseInterface *newDatabaseInterface = new Servatrice_DatabaseInterface(i, server); Servatrice_DatabaseInterface *newDatabaseInterface = new Servatrice_DatabaseInterface(i, server);
Servatrice_ConnectionPool *newPool = new Servatrice_ConnectionPool(newDatabaseInterface); Servatrice_ConnectionPool *newPool = new Servatrice_ConnectionPool(newDatabaseInterface);
QThread *newThread = new QThread; QThread *newThread = new QThread;
newThread->setObjectName("pool_" + QString::number(i)); newThread->setObjectName("pool_" + QString::number(i));
newPool->moveToThread(newThread); newPool->moveToThread(newThread);
newDatabaseInterface->moveToThread(newThread); newDatabaseInterface->moveToThread(newThread);
server->addDatabaseInterface(newThread, newDatabaseInterface); server->addDatabaseInterface(newThread, newDatabaseInterface);
newThread->start(); newThread->start();
QMetaObject::invokeMethod(newDatabaseInterface, "initDatabase", Qt::BlockingQueuedConnection, Q_ARG(QSqlDatabase, _sqlDatabase)); QMetaObject::invokeMethod(newDatabaseInterface, "initDatabase", Qt::BlockingQueuedConnection, Q_ARG(QSqlDatabase, _sqlDatabase));
connectionPools.append(newPool); connectionPools.append(newPool);
} }
} }
Servatrice_GameServer::~Servatrice_GameServer() Servatrice_GameServer::~Servatrice_GameServer()
{ {
for (int i = 0; i < connectionPools.size(); ++i) { for (int i = 0; i < connectionPools.size(); ++i) {
logger->logMessage(QString("Closing pool %1...").arg(i)); logger->logMessage(QString("Closing pool %1...").arg(i));
QThread *poolThread = connectionPools[i]->thread(); QThread *poolThread = connectionPools[i]->thread();
connectionPools[i]->deleteLater(); // pool destructor calls thread()->quit() connectionPools[i]->deleteLater(); // pool destructor calls thread()->quit()
poolThread->wait(); poolThread->wait();
} }
} }
void Servatrice_GameServer::incomingConnection(int socketDescriptor) void Servatrice_GameServer::incomingConnection(int socketDescriptor)
{ {
// Determine connection pool with smallest client count // Determine connection pool with smallest client count
int minClientCount = -1; int minClientCount = -1;
int poolIndex = -1; int poolIndex = -1;
QStringList debugStr; QStringList debugStr;
for (int i = 0; i < connectionPools.size(); ++i) { for (int i = 0; i < connectionPools.size(); ++i) {
const int clientCount = connectionPools[i]->getClientCount(); const int clientCount = connectionPools[i]->getClientCount();
if ((poolIndex == -1) || (clientCount < minClientCount)) { if ((poolIndex == -1) || (clientCount < minClientCount)) {
minClientCount = clientCount; minClientCount = clientCount;
poolIndex = i; poolIndex = i;
} }
debugStr.append(QString::number(clientCount)); debugStr.append(QString::number(clientCount));
} }
qDebug() << "Pool utilisation:" << debugStr; qDebug() << "Pool utilisation:" << debugStr;
Servatrice_ConnectionPool *pool = connectionPools[poolIndex]; Servatrice_ConnectionPool *pool = connectionPools[poolIndex];
ServerSocketInterface *ssi = new ServerSocketInterface(server, pool->getDatabaseInterface()); ServerSocketInterface *ssi = new ServerSocketInterface(server, pool->getDatabaseInterface());
ssi->moveToThread(pool->thread()); ssi->moveToThread(pool->thread());
pool->addClient(); pool->addClient();
connect(ssi, SIGNAL(destroyed()), pool, SLOT(removeClient())); connect(ssi, SIGNAL(destroyed()), pool, SLOT(removeClient()));
QMetaObject::invokeMethod(ssi, "initConnection", Qt::QueuedConnection, Q_ARG(int, socketDescriptor)); QMetaObject::invokeMethod(ssi, "initConnection", Qt::QueuedConnection, Q_ARG(int, socketDescriptor));
} }
void Servatrice_IslServer::incomingConnection(int socketDescriptor) void Servatrice_IslServer::incomingConnection(int socketDescriptor)
{ {
QThread *thread = new QThread; QThread *thread = new QThread;
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
IslInterface *interface = new IslInterface(socketDescriptor, cert, privateKey, server); IslInterface *interface = new IslInterface(socketDescriptor, cert, privateKey, server);
interface->moveToThread(thread); interface->moveToThread(thread);
connect(interface, SIGNAL(destroyed()), thread, SLOT(quit())); connect(interface, SIGNAL(destroyed()), thread, SLOT(quit()));
thread->start(); thread->start();
QMetaObject::invokeMethod(interface, "initServer", Qt::QueuedConnection); QMetaObject::invokeMethod(interface, "initServer", Qt::QueuedConnection);
} }
Servatrice::Servatrice(QSettings *_settings, QObject *parent) 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>("QSqlDatabase"); qRegisterMetaType<QSqlDatabase>("QSqlDatabase");
} }
Servatrice::~Servatrice() Servatrice::~Servatrice()
{ {
gameServer->close(); gameServer->close();
prepareDestroy(); prepareDestroy();
} }
bool Servatrice::initServer() bool Servatrice::initServer()
{ {
serverName = settings->value("server/name").toString(); serverName = settings->value("server/name").toString();
serverId = settings->value("server/id", 0).toInt(); serverId = settings->value("server/id", 0).toInt();
bool regServerOnly = settings->value("server/regonly", 0).toBool(); bool regServerOnly = settings->value("server/regonly", 0).toBool();
const QString authenticationMethodStr = settings->value("authentication/method").toString(); const QString authenticationMethodStr = settings->value("authentication/method").toString();
if (authenticationMethodStr == "sql") { if (authenticationMethodStr == "sql") {
authenticationMethod = AuthenticationSql; authenticationMethod = AuthenticationSql;
} else { } else {
if (regServerOnly) { if (regServerOnly) {
qDebug() << "Registration only server enabled but no DB Connection : Error."; qDebug() << "Registration only server enabled but no DB Connection : Error.";
return false; return false;
} }
authenticationMethod = AuthenticationNone; authenticationMethod = AuthenticationNone;
} }
QString dbTypeStr = settings->value("database/type").toString(); QString dbTypeStr = settings->value("database/type").toString();
if (dbTypeStr == "mysql") if (dbTypeStr == "mysql")
databaseType = DatabaseMySql; databaseType = DatabaseMySql;
else else
databaseType = DatabaseNone; databaseType = DatabaseNone;
servatriceDatabaseInterface = new Servatrice_DatabaseInterface(-1, this); servatriceDatabaseInterface = new Servatrice_DatabaseInterface(-1, this);
setDatabaseInterface(servatriceDatabaseInterface); setDatabaseInterface(servatriceDatabaseInterface);
if (databaseType != DatabaseNone) { if (databaseType != DatabaseNone) {
settings->beginGroup("database"); settings->beginGroup("database");
dbPrefix = settings->value("prefix").toString(); dbPrefix = settings->value("prefix").toString();
servatriceDatabaseInterface->initDatabase("QMYSQL", servatriceDatabaseInterface->initDatabase("QMYSQL",
settings->value("hostname").toString(), settings->value("hostname").toString(),
settings->value("database").toString(), settings->value("database").toString(),
settings->value("user").toString(), settings->value("user").toString(),
settings->value("password").toString()); settings->value("password").toString());
settings->endGroup(); settings->endGroup();
updateServerList(); updateServerList();
qDebug() << "Clearing previous sessions..."; qDebug() << "Clearing previous sessions...";
servatriceDatabaseInterface->clearSessionTables(); servatriceDatabaseInterface->clearSessionTables();
} }
const QString roomMethod = settings->value("rooms/method").toString(); const QString roomMethod = settings->value("rooms/method").toString();
if (roomMethod == "sql") { if (roomMethod == "sql") {
QSqlQuery query(servatriceDatabaseInterface->getDatabase()); QSqlQuery query(servatriceDatabaseInterface->getDatabase());
query.prepare("select id, name, descr, auto_join, join_message from " + dbPrefix + "_rooms order by id asc"); query.prepare("select id, name, descr, auto_join, join_message from " + dbPrefix + "_rooms order by id asc");
servatriceDatabaseInterface->execSqlQuery(query); servatriceDatabaseInterface->execSqlQuery(query);
while (query.next()) { while (query.next()) {
QSqlQuery query2(servatriceDatabaseInterface->getDatabase()); QSqlQuery query2(servatriceDatabaseInterface->getDatabase());
query2.prepare("select name from " + dbPrefix + "_rooms_gametypes where id_room = :id_room"); query2.prepare("select name from " + dbPrefix + "_rooms_gametypes where id_room = :id_room");
query2.bindValue(":id_room", query.value(0).toInt()); query2.bindValue(":id_room", query.value(0).toInt());
servatriceDatabaseInterface->execSqlQuery(query2); servatriceDatabaseInterface->execSqlQuery(query2);
QStringList gameTypes; QStringList gameTypes;
while (query2.next()) while (query2.next())
gameTypes.append(query2.value(0).toString()); gameTypes.append(query2.value(0).toString());
addRoom(new Server_Room(query.value(0).toInt(), addRoom(new Server_Room(query.value(0).toInt(),
query.value(1).toString(), query.value(1).toString(),
query.value(2).toString(), query.value(2).toString(),
query.value(3).toInt(), query.value(3).toInt(),
query.value(4).toString(), query.value(4).toString(),
gameTypes, gameTypes,
this this
)); ));
} }
} else { } else {
int size = settings->beginReadArray("rooms/roomlist"); int size = settings->beginReadArray("rooms/roomlist");
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
settings->setArrayIndex(i); settings->setArrayIndex(i);
QStringList gameTypes; QStringList gameTypes;
int size2 = settings->beginReadArray("game_types"); int size2 = settings->beginReadArray("game_types");
for (int j = 0; j < size2; ++j) { for (int j = 0; j < size2; ++j) {
settings->setArrayIndex(j); settings->setArrayIndex(j);
gameTypes.append(settings->value("name").toString()); gameTypes.append(settings->value("name").toString());
} }
settings->endArray(); settings->endArray();
Server_Room *newRoom = new Server_Room( Server_Room *newRoom = new Server_Room(
i, i,
settings->value("name").toString(), settings->value("name").toString(),
settings->value("description").toString(), settings->value("description").toString(),
settings->value("autojoin").toBool(), settings->value("autojoin").toBool(),
settings->value("joinmessage").toString(), settings->value("joinmessage").toString(),
gameTypes, gameTypes,
this this
); );
addRoom(newRoom); addRoom(newRoom);
} }
settings->endArray(); settings->endArray();
} }
updateLoginMessage(); updateLoginMessage();
maxGameInactivityTime = settings->value("game/max_game_inactivity_time").toInt(); maxGameInactivityTime = settings->value("game/max_game_inactivity_time").toInt();
maxPlayerInactivityTime = settings->value("game/max_player_inactivity_time").toInt(); maxPlayerInactivityTime = settings->value("game/max_player_inactivity_time").toInt();
maxUsersPerAddress = settings->value("security/max_users_per_address").toInt(); maxUsersPerAddress = settings->value("security/max_users_per_address").toInt();
messageCountingInterval = settings->value("security/message_counting_interval").toInt(); messageCountingInterval = settings->value("security/message_counting_interval").toInt();
maxMessageCountPerInterval = settings->value("security/max_message_count_per_interval").toInt(); maxMessageCountPerInterval = settings->value("security/max_message_count_per_interval").toInt();
maxMessageSizePerInterval = settings->value("security/max_message_size_per_interval").toInt(); maxMessageSizePerInterval = settings->value("security/max_message_size_per_interval").toInt();
maxGamesPerUser = settings->value("security/max_games_per_user").toInt(); maxGamesPerUser = settings->value("security/max_games_per_user").toInt();
try { if (settings->value("servernetwork/active", 0).toInt()) { try { if (settings->value("servernetwork/active", 0).toInt()) {
qDebug() << "Connecting to ISL network."; qDebug() << "Connecting to ISL network.";
const QString certFileName = settings->value("servernetwork/ssl_cert").toString(); const QString certFileName = settings->value("servernetwork/ssl_cert").toString();
const QString keyFileName = settings->value("servernetwork/ssl_key").toString(); const QString keyFileName = settings->value("servernetwork/ssl_key").toString();
qDebug() << "Loading certificate..."; qDebug() << "Loading certificate...";
QFile certFile(certFileName); QFile certFile(certFileName);
if (!certFile.open(QIODevice::ReadOnly)) if (!certFile.open(QIODevice::ReadOnly))
throw QString("Error opening certificate file: %1").arg(certFileName); throw QString("Error opening certificate file: %1").arg(certFileName);
QSslCertificate cert(&certFile); QSslCertificate cert(&certFile);
if (!cert.isValid()) if (!cert.isValid())
throw(QString("Invalid certificate.")); throw(QString("Invalid certificate."));
qDebug() << "Loading private key..."; qDebug() << "Loading private key...";
QFile keyFile(keyFileName); QFile keyFile(keyFileName);
if (!keyFile.open(QIODevice::ReadOnly)) if (!keyFile.open(QIODevice::ReadOnly))
throw QString("Error opening private key file: %1").arg(keyFileName); throw QString("Error opening private key file: %1").arg(keyFileName);
QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
if (key.isNull()) if (key.isNull())
throw QString("Invalid private key."); throw QString("Invalid private key.");
QMutableListIterator<ServerProperties> serverIterator(serverList); QMutableListIterator<ServerProperties> serverIterator(serverList);
while (serverIterator.hasNext()) { while (serverIterator.hasNext()) {
const ServerProperties &prop = serverIterator.next(); const ServerProperties &prop = serverIterator.next();
if (prop.cert == cert) { if (prop.cert == cert) {
serverIterator.remove(); serverIterator.remove();
continue; continue;
} }
QThread *thread = new QThread; QThread *thread = new QThread;
thread->setObjectName("isl_" + QString::number(prop.id)); thread->setObjectName("isl_" + QString::number(prop.id));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 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); IslInterface *interface = new IslInterface(prop.id, prop.hostname, prop.address.toString(), prop.controlPort, prop.cert, cert, key, this);
interface->moveToThread(thread); interface->moveToThread(thread);
connect(interface, SIGNAL(destroyed()), thread, SLOT(quit())); connect(interface, SIGNAL(destroyed()), thread, SLOT(quit()));
thread->start(); thread->start();
QMetaObject::invokeMethod(interface, "initClient", Qt::BlockingQueuedConnection); QMetaObject::invokeMethod(interface, "initClient", Qt::BlockingQueuedConnection);
} }
const int networkPort = settings->value("servernetwork/port", 14747).toInt(); const int networkPort = settings->value("servernetwork/port", 14747).toInt();
qDebug() << "Starting ISL server on port" << networkPort; qDebug() << "Starting ISL server on port" << networkPort;
islServer = new Servatrice_IslServer(this, cert, key, this); islServer = new Servatrice_IslServer(this, cert, key, this);
if (islServer->listen(QHostAddress::Any, networkPort)) if (islServer->listen(QHostAddress::Any, networkPort))
qDebug() << "ISL server listening."; qDebug() << "ISL server listening.";
else else
throw QString("islServer->listen()"); throw QString("islServer->listen()");
} } catch (QString error) { } } catch (QString error) {
qDebug() << "ERROR --" << error; qDebug() << "ERROR --" << error;
return false; return false;
} }
pingClock = new QTimer(this); pingClock = new QTimer(this);
connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout())); connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout()));
pingClock->start(1000); pingClock->start(1000);
int statusUpdateTime = settings->value("server/statusupdate").toInt(); int statusUpdateTime = settings->value("server/statusupdate").toInt();
statusUpdateClock = new QTimer(this); statusUpdateClock = new QTimer(this);
connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate())); connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate()));
if (statusUpdateTime != 0) { if (statusUpdateTime != 0) {
qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms"; qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms";
statusUpdateClock->start(statusUpdateTime); statusUpdateClock->start(statusUpdateTime);
} }
const int numberPools = settings->value("server/number_pools", 1).toInt(); const int numberPools = settings->value("server/number_pools", 1).toInt();
gameServer = new Servatrice_GameServer(this, numberPools, servatriceDatabaseInterface->getDatabase(), this); gameServer = new Servatrice_GameServer(this, numberPools, servatriceDatabaseInterface->getDatabase(), this);
gameServer->setMaxPendingConnections(1000); gameServer->setMaxPendingConnections(1000);
const int gamePort = settings->value("server/port", 4747).toInt(); const int gamePort = settings->value("server/port", 4747).toInt();
qDebug() << "Starting server on port" << gamePort; qDebug() << "Starting server on port" << gamePort;
if (gameServer->listen(QHostAddress::Any, gamePort)) if (gameServer->listen(QHostAddress::Any, gamePort))
qDebug() << "Server listening."; qDebug() << "Server listening.";
else { else {
qDebug() << "gameServer->listen(): Error."; qDebug() << "gameServer->listen(): Error.";
return false; return false;
} }
return true; return true;
} }
void Servatrice::addDatabaseInterface(QThread *thread, Servatrice_DatabaseInterface *databaseInterface) void Servatrice::addDatabaseInterface(QThread *thread, Servatrice_DatabaseInterface *databaseInterface)
{ {
databaseInterfaces.insert(thread, databaseInterface); databaseInterfaces.insert(thread, databaseInterface);
} }
void Servatrice::updateServerList() void Servatrice::updateServerList()
{ {
qDebug() << "Updating server list..."; qDebug() << "Updating server list...";
serverListMutex.lock(); serverListMutex.lock();
serverList.clear(); serverList.clear();
QSqlQuery query(servatriceDatabaseInterface->getDatabase()); QSqlQuery query(servatriceDatabaseInterface->getDatabase());
query.prepare("select id, ssl_cert, hostname, address, game_port, control_port from " + dbPrefix + "_servers order by id asc"); query.prepare("select id, ssl_cert, hostname, address, game_port, control_port from " + dbPrefix + "_servers order by id asc");
servatriceDatabaseInterface->execSqlQuery(query); servatriceDatabaseInterface->execSqlQuery(query);
while (query.next()) { 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()); 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); 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); 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(); serverListMutex.unlock();
} }
QList<ServerProperties> Servatrice::getServerList() const QList<ServerProperties> Servatrice::getServerList() const
{ {
serverListMutex.lock(); serverListMutex.lock();
QList<ServerProperties> result = serverList; QList<ServerProperties> result = serverList;
serverListMutex.unlock(); serverListMutex.unlock();
return result; return result;
} }
int Servatrice::getUsersWithAddress(const QHostAddress &address) const int Servatrice::getUsersWithAddress(const QHostAddress &address) const
{ {
int result = 0; int result = 0;
QReadLocker locker(&clientsLock); QReadLocker locker(&clientsLock);
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (static_cast<ServerSocketInterface *>(clients[i])->getPeerAddress() == address) if (static_cast<ServerSocketInterface *>(clients[i])->getPeerAddress() == address)
++result; ++result;
return result; return result;
} }
QList<ServerSocketInterface *> Servatrice::getUsersWithAddressAsList(const QHostAddress &address) const QList<ServerSocketInterface *> Servatrice::getUsersWithAddressAsList(const QHostAddress &address) const
{ {
QList<ServerSocketInterface *> result; QList<ServerSocketInterface *> result;
QReadLocker locker(&clientsLock); QReadLocker locker(&clientsLock);
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
if (static_cast<ServerSocketInterface *>(clients[i])->getPeerAddress() == address) if (static_cast<ServerSocketInterface *>(clients[i])->getPeerAddress() == address)
result.append(static_cast<ServerSocketInterface *>(clients[i])); result.append(static_cast<ServerSocketInterface *>(clients[i]));
return result; return result;
} }
void Servatrice::updateLoginMessage() void Servatrice::updateLoginMessage()
{ {
if (!servatriceDatabaseInterface->checkSql()) if (!servatriceDatabaseInterface->checkSql())
return; return;
QSqlQuery query(servatriceDatabaseInterface->getDatabase()); QSqlQuery query(servatriceDatabaseInterface->getDatabase());
query.prepare("select message from " + dbPrefix + "_servermessages where id_server = :id_server order by timest desc limit 1"); query.prepare("select message from " + dbPrefix + "_servermessages where id_server = :id_server order by timest desc limit 1");
query.bindValue(":id_server", serverId); query.bindValue(":id_server", serverId);
if (servatriceDatabaseInterface->execSqlQuery(query)) if (servatriceDatabaseInterface->execSqlQuery(query))
if (query.next()) { if (query.next()) {
const QString newLoginMessage = query.value(0).toString(); const QString newLoginMessage = query.value(0).toString();
loginMessageMutex.lock(); loginMessageMutex.lock();
loginMessage = newLoginMessage; loginMessage = newLoginMessage;
loginMessageMutex.unlock(); loginMessageMutex.unlock();
Event_ServerMessage event; Event_ServerMessage event;
event.set_message(newLoginMessage.toStdString()); event.set_message(newLoginMessage.toStdString());
SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event);
QMapIterator<QString, Server_ProtocolHandler *> usersIterator(users); QMapIterator<QString, Server_ProtocolHandler *> usersIterator(users);
while (usersIterator.hasNext()) while (usersIterator.hasNext())
usersIterator.next().value()->sendProtocolItem(*se); usersIterator.next().value()->sendProtocolItem(*se);
delete se; delete se;
} }
} }
void Servatrice::statusUpdate() void Servatrice::statusUpdate()
{ {
if (!servatriceDatabaseInterface->checkSql()) if (!servatriceDatabaseInterface->checkSql())
return; return;
const int uc = getUsersCount(); // for correct mutex locking order const int uc = getUsersCount(); // for correct mutex locking order
const int gc = getGamesCount(); const int gc = getGamesCount();
uptime += statusUpdateClock->interval() / 1000; uptime += statusUpdateClock->interval() / 1000;
txBytesMutex.lock(); txBytesMutex.lock();
quint64 tx = txBytes; quint64 tx = txBytes;
txBytes = 0; txBytes = 0;
txBytesMutex.unlock(); txBytesMutex.unlock();
rxBytesMutex.lock(); rxBytesMutex.lock();
quint64 rx = rxBytes; quint64 rx = rxBytes;
rxBytes = 0; rxBytes = 0;
rxBytesMutex.unlock(); rxBytesMutex.unlock();
QSqlQuery query(servatriceDatabaseInterface->getDatabase()); 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.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(":id", serverId);
query.bindValue(":uptime", uptime); query.bindValue(":uptime", uptime);
query.bindValue(":users_count", uc); query.bindValue(":users_count", uc);
query.bindValue(":games_count", gc); query.bindValue(":games_count", gc);
query.bindValue(":tx", tx); query.bindValue(":tx", tx);
query.bindValue(":rx", rx); query.bindValue(":rx", rx);
servatriceDatabaseInterface->execSqlQuery(query); servatriceDatabaseInterface->execSqlQuery(query);
} }
void Servatrice::scheduleShutdown(const QString &reason, int minutes) void Servatrice::scheduleShutdown(const QString &reason, int minutes)
{ {
shutdownReason = reason; shutdownReason = reason;
shutdownMinutes = minutes + 1; shutdownMinutes = minutes + 1;
if (minutes > 0) { if (minutes > 0) {
shutdownTimer = new QTimer; shutdownTimer = new QTimer;
connect(shutdownTimer, SIGNAL(timeout()), this, SLOT(shutdownTimeout())); connect(shutdownTimer, SIGNAL(timeout()), this, SLOT(shutdownTimeout()));
shutdownTimer->start(60000); shutdownTimer->start(60000);
} }
shutdownTimeout(); shutdownTimeout();
} }
void Servatrice::incTxBytes(quint64 num) void Servatrice::incTxBytes(quint64 num)
{ {
txBytesMutex.lock(); txBytesMutex.lock();
txBytes += num; txBytes += num;
txBytesMutex.unlock(); txBytesMutex.unlock();
} }
void Servatrice::incRxBytes(quint64 num) void Servatrice::incRxBytes(quint64 num)
{ {
rxBytesMutex.lock(); rxBytesMutex.lock();
rxBytes += num; rxBytes += num;
rxBytesMutex.unlock(); rxBytesMutex.unlock();
} }
void Servatrice::shutdownTimeout() void Servatrice::shutdownTimeout()
{ {
--shutdownMinutes; --shutdownMinutes;
SessionEvent *se; SessionEvent *se;
if (shutdownMinutes) { if (shutdownMinutes) {
Event_ServerShutdown event; Event_ServerShutdown event;
event.set_reason(shutdownReason.toStdString()); event.set_reason(shutdownReason.toStdString());
event.set_minutes(shutdownMinutes); event.set_minutes(shutdownMinutes);
se = Server_ProtocolHandler::prepareSessionEvent(event); se = Server_ProtocolHandler::prepareSessionEvent(event);
} else { } else {
Event_ConnectionClosed event; Event_ConnectionClosed event;
event.set_reason(Event_ConnectionClosed::SERVER_SHUTDOWN); event.set_reason(Event_ConnectionClosed::SERVER_SHUTDOWN);
se = Server_ProtocolHandler::prepareSessionEvent(event); se = Server_ProtocolHandler::prepareSessionEvent(event);
} }
clientsLock.lockForRead(); clientsLock.lockForRead();
for (int i = 0; i < clients.size(); ++i) for (int i = 0; i < clients.size(); ++i)
clients[i]->sendProtocolItem(*se); clients[i]->sendProtocolItem(*se);
clientsLock.unlock(); clientsLock.unlock();
delete se; delete se;
if (!shutdownMinutes) if (!shutdownMinutes)
deleteLater(); deleteLater();
} }
bool Servatrice::islConnectionExists(int serverId) const bool Servatrice::islConnectionExists(int serverId) const
{ {
// Only call with islLock locked at least for reading // Only call with islLock locked at least for reading
return islInterfaces.contains(serverId); return islInterfaces.contains(serverId);
} }
void Servatrice::addIslInterface(int serverId, IslInterface *interface) void Servatrice::addIslInterface(int serverId, IslInterface *interface)
{ {
// Only call with islLock locked for writing // Only call with islLock locked for writing
islInterfaces.insert(serverId, interface); islInterfaces.insert(serverId, interface);
connect(interface, SIGNAL(externalUserJoined(ServerInfo_User)), this, SLOT(externalUserJoined(ServerInfo_User))); connect(interface, SIGNAL(externalUserJoined(ServerInfo_User)), this, SLOT(externalUserJoined(ServerInfo_User)));
connect(interface, SIGNAL(externalUserLeft(QString)), this, SLOT(externalUserLeft(QString))); 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(externalRoomUserJoined(int, ServerInfo_User)), this, SLOT(externalRoomUserJoined(int, ServerInfo_User)));
connect(interface, SIGNAL(externalRoomUserLeft(int, QString)), this, SLOT(externalRoomUserLeft(int, QString))); 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(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(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(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(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(responseReceived(Response, qint64)), this, SLOT(externalResponseReceived(Response, qint64)));
connect(interface, SIGNAL(gameEventContainerReceived(GameEventContainer, qint64)), this, SLOT(externalGameEventContainerReceived(GameEventContainer, qint64))); connect(interface, SIGNAL(gameEventContainerReceived(GameEventContainer, qint64)), this, SLOT(externalGameEventContainerReceived(GameEventContainer, qint64)));
} }
void Servatrice::removeIslInterface(int serverId) void Servatrice::removeIslInterface(int serverId)
{ {
// Only call with islLock locked for writing // Only call with islLock locked for writing
// XXX we probably need to delete everything that belonged to it... // XXX we probably need to delete everything that belonged to it...
islInterfaces.remove(serverId); islInterfaces.remove(serverId);
} }
void Servatrice::doSendIslMessage(const IslMessage &msg, int serverId) void Servatrice::doSendIslMessage(const IslMessage &msg, int serverId)
{ {
QReadLocker locker(&islLock); QReadLocker locker(&islLock);
if (serverId == -1) { if (serverId == -1) {
QMapIterator<int, IslInterface *> islIterator(islInterfaces); QMapIterator<int, IslInterface *> islIterator(islInterfaces);
while (islIterator.hasNext()) while (islIterator.hasNext())
islIterator.next().value()->transmitMessage(msg); islIterator.next().value()->transmitMessage(msg);
} else { } else {
IslInterface *interface = islInterfaces.value(serverId); IslInterface *interface = islInterfaces.value(serverId);
if (interface) if (interface)
interface->transmitMessage(msg); interface->transmitMessage(msg);
} }
} }