initial commit for connection pools

This commit is contained in:
Max-Wilhelm Bruker 2012-05-20 18:47:28 +02:00
parent c2edd33e90
commit 981db47f9e
21 changed files with 829 additions and 700 deletions

View file

@ -13,6 +13,7 @@ SET(common_SOURCES
server_card.cpp
server_cardzone.cpp
server_counter.cpp
server_database_interface.cpp
server_game.cpp
server_player.cpp
server_protocolhandler.cpp
@ -30,6 +31,7 @@ SET(common_HEADERS
server.h
server_arrowtarget.h
server_card.h
server_database_interface.h
server_game.h
server_player.h
server_protocolhandler.h

View file

@ -25,6 +25,7 @@
#include "server_protocolhandler.h"
#include "server_remoteuserinterface.h"
#include "server_metatypes.h"
#include "server_database_interface.h"
#include "pb/event_user_joined.pb.h"
#include "pb/event_user_left.pb.h"
#include "pb/event_list_rooms.pb.h"
@ -34,7 +35,7 @@
#include <QDebug>
Server::Server(QObject *parent)
: QObject(parent), nextGameId(0), nextReplayId(0), clientsLock(QReadWriteLock::Recursive)
: QObject(parent), databaseInterface(0), clientsLock(QReadWriteLock::Recursive)
{
qRegisterMetaType<ServerInfo_Game>("ServerInfo_Game");
qRegisterMetaType<ServerInfo_Room>("ServerInfo_Room");
@ -67,27 +68,33 @@ void Server::prepareDestroy()
roomsLock.unlock();
}
AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr, int &secondsLeft)
void Server::setDatabaseInterface(Server_DatabaseInterface *_databaseInterface)
{
databaseInterface = _databaseInterface;
connect(this, SIGNAL(endSession(qint64)), databaseInterface, SLOT(endSession(qint64)));
}
AuthenticationResult Server::loginUser(Server_DatabaseInterface *sessionDatabaseInterface, Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr, int &secondsLeft)
{
if (name.size() > 35)
name = name.left(35);
QWriteLocker locker(&clientsLock);
AuthenticationResult authState = checkUserPassword(session, name, password, reasonStr, secondsLeft);
AuthenticationResult authState = sessionDatabaseInterface->checkUserPassword(session, name, password, reasonStr, secondsLeft);
if ((authState == NotLoggedIn) || (authState == UserIsBanned))
return authState;
ServerInfo_User data = getUserData(name, true);
ServerInfo_User data = sessionDatabaseInterface->getUserData(name, true);
data.set_address(session->getAddress().toStdString());
name = QString::fromStdString(data.name()); // Compensate for case indifference
lockSessionTables();
sessionDatabaseInterface->lockSessionTables();
if (authState == PasswordRight) {
if (users.contains(name) || userSessionExists(name)) {
if (users.contains(name) || sessionDatabaseInterface->userSessionExists(name)) {
qDebug("Login denied: would overwrite old session");
unlockSessionTables();
sessionDatabaseInterface->unlockSessionTables();
return WouldOverwriteOldSession;
}
} else if (authState == UnknownUser) {
@ -95,7 +102,7 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString
// don't interfere with registered user names though.
QString tempName = name;
int i = 0;
while (users.contains(tempName) || userExists(tempName) || userSessionExists(tempName))
while (users.contains(tempName) || sessionDatabaseInterface->userExists(tempName) || sessionDatabaseInterface->userSessionExists(tempName))
tempName = name + "_" + QString::number(++i);
name = tempName;
data.set_name(name.toStdString());
@ -104,8 +111,8 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString
users.insert(name, session);
qDebug() << "Server::loginUser: name=" << name;
data.set_session_id(startSession(name, session->getAddress()));
unlockSessionTables();
data.set_session_id(sessionDatabaseInterface->startSession(name, session->getAddress()));
sessionDatabaseInterface->unlockSessionTables();
usersBySessionId.insert(data.session_id(), session);
@ -176,7 +183,7 @@ void Server::removeClient(Server_ProtocolHandler *client)
if (data->has_session_id()) {
const qint64 sessionId = data->session_id();
usersBySessionId.remove(sessionId);
endSession(sessionId);
emit endSession(sessionId);
qDebug() << "closed session id:" << sessionId;
}
}
@ -325,7 +332,7 @@ void Server::externalJoinGameCommandReceived(const Command_JoinGame &cmd, int cm
}
ResponseContainer responseContainer(cmdId);
Response::ResponseCode responseCode = room->processJoinGameCommand(cmd, responseContainer, userInterface);
Response::ResponseCode responseCode = room->processJoinGameCommand(cmd, responseContainer, userInterface, databaseInterface);
userInterface->sendResponseContainer(responseContainer, responseCode);
} catch (Response::ResponseCode code) {
Response response;

View file

@ -10,6 +10,7 @@
#include "pb/serverinfo_user.pb.h"
#include "server_player_reference.h"
class Server_DatabaseInterface;
class Server_Game;
class Server_Room;
class Server_ProtocolHandler;
@ -35,16 +36,15 @@ signals:
void pingClockTimeout();
void sigSendIslMessage(const IslMessage &message, int serverId);
void logDebugMessage(QString message, void *caller);
void endSession(qint64 sessionId);
private slots:
void broadcastRoomUpdate(const ServerInfo_Room &roomInfo, bool sendToIsl = false);
public:
mutable QReadWriteLock clientsLock, roomsLock; // locking order: roomsLock before clientsLock
Server(QObject *parent = 0);
~Server();
AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reason, int &secondsLeft);
AuthenticationResult loginUser(Server_DatabaseInterface *sessionDatabaseInterface, Server_ProtocolHandler *session, QString &name, const QString &password, QString &reason, int &secondsLeft);
const QMap<int, Server_Room *> &getRooms() { return rooms; }
virtual int getNextGameId() { return nextGameId++; }
virtual int getNextReplayId() { return nextReplayId++; }
const QMap<QString, Server_ProtocolHandler *> &getUsers() const { return users; }
const QMap<qint64, Server_ProtocolHandler *> &getUsersBySessionId() const { return usersBySessionId; }
@ -61,11 +61,6 @@ public:
virtual int getMaxGamesPerUser() const { return 0; }
virtual bool getThreaded() const { return false; }
virtual QMap<QString, ServerInfo_User> getBuddyList(const QString &name) { return QMap<QString, ServerInfo_User>(); }
virtual QMap<QString, ServerInfo_User> getIgnoreList(const QString &name) { return QMap<QString, ServerInfo_User>(); }
virtual bool isInBuddyList(const QString &whoseList, const QString &who) { return false; }
virtual bool isInIgnoreList(const QString &whoseList, const QString &who) { return false; }
virtual void storeGameInformation(int secondsElapsed, const QSet<QString> &allPlayersEver, const QSet<QString> &allSpectatorsEver, const QList<GameReplay *> &replays) { }
virtual DeckList *getDeckFromDatabase(int deckId, const QString &userName) { return 0; }
@ -101,6 +96,8 @@ protected slots:
virtual void doSendIslMessage(const IslMessage &msg, int serverId) { }
protected:
void prepareDestroy();
void setDatabaseInterface(Server_DatabaseInterface *_databaseInterface);
Server_DatabaseInterface *databaseInterface;
QList<Server_ProtocolHandler *> clients;
QMap<qint64, Server_ProtocolHandler *> usersBySessionId;
QMap<QString, Server_ProtocolHandler *> users;
@ -108,20 +105,9 @@ protected:
QMap<QString, Server_AbstractUserInterface *> externalUsers;
QMap<int, Server_Room *> rooms;
virtual qint64 startSession(const QString &userName, const QString &address) { return 0; }
virtual void endSession(qint64 sessionId) { }
virtual bool userExists(const QString &user) { return false; }
virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reason, int &secondsLeft) { return UnknownUser; }
virtual ServerInfo_User getUserData(const QString &name, bool withId = false) = 0;
int getUsersCount() const;
int getGamesCount() const;
int nextGameId, nextReplayId;
void addRoom(Server_Room *newRoom);
virtual void clearSessionTables() { }
virtual void lockSessionTables() { }
virtual void unlockSessionTables() { }
virtual bool userSessionExists(const QString &userName) { return false; }
};
#endif

View file

@ -0,0 +1,7 @@
#include "server_database_interface.h"
Server_DatabaseInterface::Server_DatabaseInterface()
: nextGameId(0),
nextReplayId(0)
{
}

View file

@ -0,0 +1,36 @@
#ifndef SERVER_DATABASE_INTERFACE_H
#define SERVER_DATABASE_INTERFACE_H
#include <QObject>
#include "server.h"
class Server_DatabaseInterface : public QObject {
Q_OBJECT
private:
int nextGameId, nextReplayId;
public:
Server_DatabaseInterface();
virtual AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, QString &reasonStr, int &secondsLeft) = 0;
virtual bool userExists(const QString &user) { return false; }
virtual QMap<QString, ServerInfo_User> getBuddyList(const QString &name) { return QMap<QString, ServerInfo_User>(); }
virtual QMap<QString, ServerInfo_User> getIgnoreList(const QString &name) { return QMap<QString, ServerInfo_User>(); }
virtual bool isInBuddyList(const QString &whoseList, const QString &who) { return false; }
virtual bool isInIgnoreList(const QString &whoseList, const QString &who) { return false; }
virtual ServerInfo_User getUserData(const QString &name, bool withId = false) = 0;
virtual qint64 startSession(const QString &userName, const QString &address) { return 0; }
public slots:
virtual void endSession(qint64 sessionId) { }
public:
virtual int getNextGameId() { return nextGameId++; }
virtual int getNextReplayId() { return nextReplayId++; }
virtual void clearSessionTables() { }
virtual void lockSessionTables() { }
virtual void unlockSessionTables() { }
virtual bool userSessionExists(const QString &userName) { return false; }
};
#endif

View file

@ -25,6 +25,7 @@
#include "server_arrow.h"
#include "server_card.h"
#include "server_cardzone.h"
#include "server_database_interface.h"
#include "decklist.h"
#include "pb/context_connection_state_changed.pb.h"
#include "pb/context_ping_changed.pb.h"
@ -339,7 +340,7 @@ void Server_Game::stopGameIfFinished()
emit gameInfoChanged(gameInfo);
}
Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions)
Response::ResponseCode Server_Game::checkJoin(Server_DatabaseInterface *databaseInterface, ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions)
{
{
QMapIterator<int, Server_Player *> playerIterator(players);
@ -353,9 +354,9 @@ Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user, const QStri
if (!(user->user_level() & ServerInfo_User::IsRegistered) && onlyRegistered)
return Response::RespUserLevelTooLow;
if (onlyBuddies)
if (!room->getServer()->isInBuddyList(QString::fromStdString(creatorInfo->name()), QString::fromStdString(user->name())))
if (!databaseInterface->isInBuddyList(QString::fromStdString(creatorInfo->name()), QString::fromStdString(user->name())))
return Response::RespOnlyBuddies;
if (room->getServer()->isInIgnoreList(QString::fromStdString(creatorInfo->name()), QString::fromStdString(user->name())))
if (databaseInterface->isInIgnoreList(QString::fromStdString(creatorInfo->name()), QString::fromStdString(user->name())))
return Response::RespInIgnoreList;
if (spectator) {
if (!spectatorsAllowed)

View file

@ -28,7 +28,6 @@
#include <QMap>
#include "server_response_containers.h"
#include "pb/response.pb.h"
//#include "pb/serverinfo_player.pb.h"
#include "pb/serverinfo_game.pb.h"
class QTimer;
@ -40,6 +39,7 @@ class ServerInfo_User;
class ServerInfo_Player;
class ServerInfo_Game;
class Server_AbstractUserInterface;
class Server_DatabaseInterface;
class Event_GameStateChanged;
class Server_Game : public QObject {
@ -99,7 +99,7 @@ public:
bool getSpectatorsNeedPassword() const { return spectatorsNeedPassword; }
bool getSpectatorsCanTalk() const { return spectatorsCanTalk; }
bool getSpectatorsSeeEverything() const { return spectatorsSeeEverything; }
Response::ResponseCode checkJoin(ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions);
Response::ResponseCode checkJoin(Server_DatabaseInterface *databaseInterface, ServerInfo_User *user, const QString &_password, bool spectator, bool overrideRestrictions);
bool containsUser(const QString &userName) const;
void addPlayer(Server_AbstractUserInterface *userInterface, ResponseContainer &rc, bool spectator, bool broadcastUpdate = true);
void removePlayer(Server_Player *player);

View file

@ -1,6 +1,7 @@
#include <QDebug>
#include <QDateTime>
#include "server_protocolhandler.h"
#include "server_database_interface.h"
#include "server_room.h"
#include "server_game.h"
#include "server_player.h"
@ -19,8 +20,15 @@
#include "pb/event_room_say.pb.h"
#include <google/protobuf/descriptor.h>
Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, QObject *parent)
: QObject(parent), Server_AbstractUserInterface(_server), authState(NotLoggedIn), acceptsUserListChanges(false), acceptsRoomListChanges(false), timeRunning(0), lastDataReceived(0)
Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, QObject *parent)
: QObject(parent),
Server_AbstractUserInterface(_server),
databaseInterface(_databaseInterface),
authState(NotLoggedIn),
acceptsUserListChanges(false),
acceptsRoomListChanges(false),
timeRunning(0),
lastDataReceived(0)
{
connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout()));
}
@ -309,7 +317,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
return Response::RespContextError;
QString reasonStr;
int banSecondsLeft = 0;
AuthenticationResult res = server->loginUser(this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft);
AuthenticationResult res = server->loginUser(databaseInterface, this, userName, QString::fromStdString(cmd.password()), reasonStr, banSecondsLeft);
switch (res) {
case UserIsBanned: {
Response_Login *re = new Response_Login;
@ -333,11 +341,11 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd
re->mutable_user_info()->CopyFrom(copyUserInfo(true));
if (authState == PasswordRight) {
QMapIterator<QString, ServerInfo_User> buddyIterator(server->getBuddyList(userName));
QMapIterator<QString, ServerInfo_User> buddyIterator(databaseInterface->getBuddyList(userName));
while (buddyIterator.hasNext())
re->add_buddy_list()->CopyFrom(buddyIterator.next().value());
QMapIterator<QString, ServerInfo_User> ignoreIterator(server->getIgnoreList(userName));
QMapIterator<QString, ServerInfo_User> ignoreIterator(databaseInterface->getIgnoreList(userName));
while (ignoreIterator.hasNext())
re->add_ignore_list()->CopyFrom(ignoreIterator.next().value());
}
@ -362,7 +370,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdMessage(const Command_Message
if (!userInterface)
return Response::RespNameNotFound;
}
if (server->isInIgnoreList(receiver, QString::fromStdString(userInfo->name())))
if (databaseInterface->isInIgnoreList(receiver, QString::fromStdString(userInfo->name())))
return Response::RespInIgnoreList;
Event_UserMessage event;
@ -488,9 +496,9 @@ Response::ResponseCode Server_ProtocolHandler::cmdListUsers(const Command_ListUs
QMapIterator<QString, Server_AbstractUserInterface *> extIterator = server->getExternalUsers();
while (extIterator.hasNext())
re->add_user_list()->CopyFrom(extIterator.next().value()->copyUserInfo(false));
server->clientsLock.unlock();
acceptsUserListChanges = true;
server->clientsLock.unlock();
rc.setResponseExtension(re);
return Response::RespOk;
@ -561,5 +569,5 @@ Response::ResponseCode Server_ProtocolHandler::cmdJoinGame(const Command_JoinGam
if (authState == NotLoggedIn)
return Response::RespLoginNeeded;
return room->processJoinGameCommand(cmd, rc, this);
return room->processJoinGameCommand(cmd, rc, this, databaseInterface);
}

View file

@ -8,6 +8,7 @@
#include "pb/response.pb.h"
#include "pb/server_message.pb.h"
class Server_DatabaseInterface;
class Server_Player;
class ServerInfo_User;
class Server_Room;
@ -43,11 +44,11 @@ class Server_ProtocolHandler : public QObject, public Server_AbstractUserInterfa
protected:
QMap<int, Server_Room *> rooms;
Server_DatabaseInterface *databaseInterface;
AuthenticationResult authState;
bool acceptsUserListChanges;
bool acceptsRoomListChanges;
private:
QList<int> messageSizeOverTime, messageCountOverTime;
int timeRunning, lastDataReceived;
QTimer *pingClock;
@ -82,12 +83,13 @@ signals:
public slots:
void prepareDestroy();
public:
Server_ProtocolHandler(Server *_server, QObject *parent = 0);
Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, QObject *parent = 0);
~Server_ProtocolHandler();
bool getAcceptsUserListChanges() const { return acceptsUserListChanges; }
bool getAcceptsRoomListChanges() const { return acceptsRoomListChanges; }
virtual QString getAddress() const = 0;
Server_DatabaseInterface *getDatabaseInterface() const { return databaseInterface; }
int getLastCommandTime() const { return timeRunning - lastDataReceived; }
void processCommandContainer(const CommandContainer &cont);

View file

@ -169,7 +169,7 @@ void Server_Room::updateExternalGameList(const ServerInfo_Game &gameInfo)
emit roomInfoChanged(getInfo(roomInfo, false, false, true));
}
Response::ResponseCode Server_Room::processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface)
Response::ResponseCode Server_Room::processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface, Server_DatabaseInterface *databaseInterface)
{
// This function is called from the Server thread and from the S_PH thread.
// server->roomsMutex is always locked.
@ -191,7 +191,7 @@ Response::ResponseCode Server_Room::processJoinGameCommand(const Command_JoinGam
QMutexLocker gameLocker(&g->gameMutex);
Response::ResponseCode result = g->checkJoin(userInterface->getUserInfo(), QString::fromStdString(cmd.password()), cmd.spectator(), cmd.override_restrictions());
Response::ResponseCode result = g->checkJoin(databaseInterface, userInterface->getUserInfo(), QString::fromStdString(cmd.password()), cmd.spectator(), cmd.override_restrictions());
if (result == Response::RespOk)
g->addPlayer(userInterface, rc, cmd.spectator());

View file

@ -10,6 +10,7 @@
#include "serverinfo_user_container.h"
#include "pb/response.pb.h"
class Server_DatabaseInterface;
class Server_ProtocolHandler;
class RoomEvent;
class ServerInfo_User;
@ -66,7 +67,7 @@ public:
const QMap<QString, ServerInfo_User_Container> &getExternalUsers() const { return externalUsers; }
void updateExternalGameList(const ServerInfo_Game &gameInfo);
Response::ResponseCode processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface);
Response::ResponseCode processJoinGameCommand(const Command_JoinGame &cmd, ResponseContainer &rc, Server_AbstractUserInterface *userInterface, Server_DatabaseInterface *databaseInterface);
void say(const QString &userName, const QString &s, bool sendToIsl = true);