mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-18 04:51:33 -07:00
Merge branch 'experimental' of git://cockatrice.git.sourceforge.net/gitroot/cockatrice/cockatrice
This commit is contained in:
commit
07317efd46
116 changed files with 22300 additions and 8904 deletions
|
|
@ -129,15 +129,20 @@ int main(int argc, char *argv[])
|
|||
if (testRandom)
|
||||
testRNG();
|
||||
|
||||
Servatrice server(settings);
|
||||
Servatrice *server = new Servatrice(settings);
|
||||
QObject::connect(server, SIGNAL(destroyed()), &app, SLOT(quit()), Qt::QueuedConnection);
|
||||
|
||||
std::cerr << "-------------------------" << std::endl;
|
||||
std::cerr << "Server initialized." << std::endl;
|
||||
|
||||
int retval = app.exec();
|
||||
|
||||
std::cerr << "Server quit." << std::endl;
|
||||
std::cerr << "-------------------------" << std::endl;
|
||||
|
||||
delete rng;
|
||||
delete settings;
|
||||
delete loggerThread;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ void Servatrice_TcpServer::incomingConnection(int socketDescriptor)
|
|||
}
|
||||
|
||||
Servatrice::Servatrice(QSettings *_settings, QObject *parent)
|
||||
: Server(parent), dbMutex(QMutex::Recursive), settings(_settings), uptime(0)
|
||||
: Server(parent), dbMutex(QMutex::Recursive), settings(_settings), uptime(0), shutdownTimer(0)
|
||||
{
|
||||
pingClock = new QTimer(this);
|
||||
connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout()));
|
||||
|
|
@ -65,8 +65,8 @@ Servatrice::Servatrice(QSettings *_settings, QObject *parent)
|
|||
statusUpdateClock->start(statusUpdateTime);
|
||||
}
|
||||
|
||||
bool threaded = settings->value("server/threaded", false).toInt();
|
||||
tcpServer = new Servatrice_TcpServer(this, threaded);
|
||||
threaded = settings->value("server/threaded", false).toInt();
|
||||
tcpServer = new Servatrice_TcpServer(this, threaded, this);
|
||||
int port = settings->value("server/port", 4747).toInt();
|
||||
qDebug() << "Starting server on port" << port;
|
||||
if (tcpServer->listen(QHostAddress::Any, port))
|
||||
|
|
@ -119,6 +119,7 @@ Servatrice::Servatrice(QSettings *_settings, QObject *parent)
|
|||
Servatrice::~Servatrice()
|
||||
{
|
||||
prepareDestroy();
|
||||
QSqlDatabase::database().close();
|
||||
}
|
||||
|
||||
bool Servatrice::openDatabase()
|
||||
|
|
@ -168,25 +169,32 @@ bool Servatrice::execSqlQuery(QSqlQuery &query)
|
|||
return false;
|
||||
}
|
||||
|
||||
AuthenticationResult Servatrice::checkUserPassword(const QString &user, const QString &password)
|
||||
AuthenticationResult Servatrice::checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password)
|
||||
{
|
||||
serverMutex.lock();
|
||||
QHostAddress address = static_cast<ServerSocketInterface *>(handler)->getPeerAddress();
|
||||
for (int i = 0; i < addressBanList.size(); ++i)
|
||||
if (address == addressBanList[i].first)
|
||||
return PasswordWrong;
|
||||
serverMutex.unlock();
|
||||
|
||||
QMutexLocker locker(&dbMutex);
|
||||
const QString method = settings->value("authentication/method").toString();
|
||||
if (method == "none")
|
||||
return UnknownUser;
|
||||
else if (method == "sql") {
|
||||
checkSql();
|
||||
|
||||
|
||||
QSqlQuery query;
|
||||
query.prepare("select banned, password from " + dbPrefix + "_users where name = :name and active = 1");
|
||||
query.prepare("select a.password, time_to_sec(timediff(now(), date_add(b.time_from, interval b.minutes minute))) < 0, b.minutes <=> 0 from " + dbPrefix + "_users a left join " + dbPrefix + "_bans b on b.id_user = a.id and b.time_from = (select max(c.time_from) from " + dbPrefix + "_bans c where c.id_user = a.id) where a.name = :name and a.active = 1");
|
||||
query.bindValue(":name", user);
|
||||
if (!execSqlQuery(query))
|
||||
return PasswordWrong;
|
||||
|
||||
if (query.next()) {
|
||||
if (query.value(0).toInt())
|
||||
if (query.value(1).toInt() || query.value(2).toInt())
|
||||
return PasswordWrong;
|
||||
if (query.value(1).toString() == password)
|
||||
if (query.value(0).toString() == password)
|
||||
return PasswordRight;
|
||||
else
|
||||
return PasswordWrong;
|
||||
|
|
@ -233,7 +241,7 @@ ServerInfo_User *Servatrice::evalUserQueryResult(const QSqlQuery &query, bool co
|
|||
|
||||
int userLevel = ServerInfo_User::IsUser | ServerInfo_User::IsRegistered;
|
||||
if (is_admin == 1)
|
||||
userLevel |= ServerInfo_User::IsAdmin;
|
||||
userLevel |= ServerInfo_User::IsAdmin | ServerInfo_User::IsModerator;
|
||||
else if (is_admin == 2)
|
||||
userLevel |= ServerInfo_User::IsModerator;
|
||||
|
||||
|
|
@ -324,19 +332,6 @@ QMap<QString, ServerInfo_User *> Servatrice::getIgnoreList(const QString &name)
|
|||
return result;
|
||||
}
|
||||
|
||||
bool Servatrice::getUserBanned(Server_ProtocolHandler *client, const QString &userName) const
|
||||
{
|
||||
QMutexLocker locker(&serverMutex);
|
||||
QHostAddress address = static_cast<ServerSocketInterface *>(client)->getPeerAddress();
|
||||
for (int i = 0; i < addressBanList.size(); ++i)
|
||||
if (address == addressBanList[i].first)
|
||||
return true;
|
||||
for (int i = 0; i < nameBanList.size(); ++i)
|
||||
if (userName == nameBanList[i].first)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Servatrice::updateBanTimer()
|
||||
{
|
||||
QMutexLocker locker(&serverMutex);
|
||||
|
|
@ -345,11 +340,6 @@ void Servatrice::updateBanTimer()
|
|||
addressBanList.removeAt(i);
|
||||
else
|
||||
++i;
|
||||
for (int i = 0; i < nameBanList.size(); )
|
||||
if (--(nameBanList[i].second) <= 0)
|
||||
nameBanList.removeAt(i);
|
||||
else
|
||||
++i;
|
||||
}
|
||||
|
||||
void Servatrice::updateLoginMessage()
|
||||
|
|
@ -374,18 +364,55 @@ void Servatrice::updateLoginMessage()
|
|||
|
||||
void Servatrice::statusUpdate()
|
||||
{
|
||||
QMutexLocker locker(&dbMutex);
|
||||
const int uc = getUsersCount(); // for correct mutex locking order
|
||||
const int gc = getGamesCount();
|
||||
|
||||
uptime += statusUpdateClock->interval() / 1000;
|
||||
|
||||
QMutexLocker locker(&dbMutex);
|
||||
checkSql();
|
||||
|
||||
QSqlQuery query;
|
||||
query.prepare("insert into " + dbPrefix + "_uptime (id_server, timest, uptime, users_count, games_count) values(:id, NOW(), :uptime, :users_count, :games_count)");
|
||||
query.bindValue(":id", serverId);
|
||||
query.bindValue(":uptime", uptime);
|
||||
query.bindValue(":users_count", getUsersCount());
|
||||
query.bindValue(":games_count", getGamesCount());
|
||||
query.bindValue(":users_count", uc);
|
||||
query.bindValue(":games_count", gc);
|
||||
execSqlQuery(query);
|
||||
}
|
||||
|
||||
const QString Servatrice::versionString = "Servatrice 0.20110527";
|
||||
void Servatrice::scheduleShutdown(const QString &reason, int minutes)
|
||||
{
|
||||
QMutexLocker locker(&serverMutex);
|
||||
|
||||
shutdownReason = reason;
|
||||
shutdownMinutes = minutes + 1;
|
||||
if (minutes > 0) {
|
||||
shutdownTimer = new QTimer;
|
||||
connect(shutdownTimer, SIGNAL(timeout()), this, SLOT(shutdownTimeout()));
|
||||
shutdownTimer->start(60000);
|
||||
}
|
||||
shutdownTimeout();
|
||||
}
|
||||
|
||||
void Servatrice::shutdownTimeout()
|
||||
{
|
||||
QMutexLocker locker(&serverMutex);
|
||||
|
||||
--shutdownMinutes;
|
||||
|
||||
GenericEvent *event;
|
||||
if (shutdownMinutes)
|
||||
event = new Event_ServerShutdown(shutdownReason, shutdownMinutes);
|
||||
else
|
||||
event = new Event_ConnectionClosed("server_shutdown");
|
||||
|
||||
for (int i = 0; i < clients.size(); ++i)
|
||||
clients[i]->sendProtocolItem(event, false);
|
||||
delete event;
|
||||
|
||||
if (!shutdownMinutes)
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
const QString Servatrice::versionString = "Servatrice 0.20110625";
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ class Servatrice : public Server
|
|||
private slots:
|
||||
void statusUpdate();
|
||||
void updateBanTimer();
|
||||
void shutdownTimeout();
|
||||
public:
|
||||
QMutex dbMutex;
|
||||
static const QString versionString;
|
||||
|
|
@ -67,18 +68,18 @@ public:
|
|||
int getMaxMessageCountPerInterval() const { return maxMessageCountPerInterval; }
|
||||
int getMaxMessageSizePerInterval() const { return maxMessageSizePerInterval; }
|
||||
int getMaxGamesPerUser() const { return maxGamesPerUser; }
|
||||
bool getThreaded() const { return threaded; }
|
||||
QString getDbPrefix() const { return dbPrefix; }
|
||||
void updateLoginMessage();
|
||||
ServerInfo_User *getUserData(const QString &name);
|
||||
int getUsersWithAddress(const QHostAddress &address) const;
|
||||
QMap<QString, ServerInfo_User *> getBuddyList(const QString &name);
|
||||
QMap<QString, ServerInfo_User *> getIgnoreList(const QString &name);
|
||||
bool getUserBanned(Server_ProtocolHandler *client, const QString &userName) const;
|
||||
void addAddressBan(const QHostAddress &address, int minutes) { addressBanList.append(QPair<QHostAddress, int>(address, minutes)); }
|
||||
void addNameBan(const QString &name, int minutes) { nameBanList.append(QPair<QString, int>(name, minutes)); }
|
||||
void scheduleShutdown(const QString &reason, int minutes);
|
||||
protected:
|
||||
bool userExists(const QString &user);
|
||||
AuthenticationResult checkUserPassword(const QString &user, const QString &password);
|
||||
AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password);
|
||||
private:
|
||||
QTimer *pingClock, *statusUpdateClock, *banTimeoutClock;
|
||||
QTcpServer *tcpServer;
|
||||
|
|
@ -86,12 +87,16 @@ private:
|
|||
QString dbPrefix;
|
||||
QSettings *settings;
|
||||
int serverId;
|
||||
bool threaded;
|
||||
int uptime;
|
||||
QList<QPair<QHostAddress, int> > addressBanList;
|
||||
QList<QPair<QString, int> > nameBanList;
|
||||
int maxGameInactivityTime, maxPlayerInactivityTime;
|
||||
int maxUsersPerAddress, messageCountingInterval, maxMessageCountPerInterval, maxMessageSizePerInterval, maxGamesPerUser;
|
||||
ServerInfo_User *evalUserQueryResult(const QSqlQuery &query, bool complete);
|
||||
|
||||
QString shutdownReason;
|
||||
int shutdownMinutes;
|
||||
QTimer *shutdownTimer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
#include "server_logger.h"
|
||||
|
||||
ServerSocketInterface::ServerSocketInterface(Servatrice *_server, QTcpSocket *_socket, QObject *parent)
|
||||
: Server_ProtocolHandler(_server, parent), servatrice(_server), socket(_socket), topLevelItem(0)
|
||||
: Server_ProtocolHandler(_server, parent), servatrice(_server), socket(_socket), topLevelItem(0), compressionSupport(false)
|
||||
{
|
||||
xmlWriter = new QXmlStreamWriter(&xmlBuffer);
|
||||
xmlReader = new QXmlStreamReader;
|
||||
|
|
@ -69,6 +69,7 @@ ServerSocketInterface::~ServerSocketInterface()
|
|||
delete xmlReader;
|
||||
delete socket;
|
||||
socket = 0;
|
||||
delete topLevelItem;
|
||||
}
|
||||
|
||||
void ServerSocketInterface::processProtocolItem(ProtocolItem *item)
|
||||
|
|
@ -102,6 +103,8 @@ void ServerSocketInterface::readClient()
|
|||
if (topLevelItem)
|
||||
topLevelItem->readElement(xmlReader);
|
||||
else if (xmlReader->isStartElement() && (xmlReader->name().toString() == "cockatrice_client_stream")) {
|
||||
if (xmlReader->attributes().value("comp").toString().toInt() == 1)
|
||||
compressionSupport = true;
|
||||
topLevelItem = new TopLevelProtocolItem;
|
||||
connect(topLevelItem, SIGNAL(protocolItemReceived(ProtocolItem *)), this, SLOT(processProtocolItem(ProtocolItem *)));
|
||||
}
|
||||
|
|
@ -296,7 +299,10 @@ ResponseCode ServerSocketInterface::cmdDeckList(Command_DeckList * /*cmd*/, Comm
|
|||
if (!deckListHelper(root))
|
||||
return RespContextError;
|
||||
|
||||
cont->setResponse(new Response_DeckList(cont->getCmdId(), RespOk, root));
|
||||
ProtocolResponse *resp = new Response_DeckList(cont->getCmdId(), RespOk, root);
|
||||
if (getCompressionSupport())
|
||||
resp->setCompressed(true);
|
||||
cont->setResponse(resp);
|
||||
|
||||
return RespNothing;
|
||||
}
|
||||
|
|
@ -455,8 +461,8 @@ ResponseCode ServerSocketInterface::cmdDeckDownload(Command_DeckDownload *cmd, C
|
|||
return RespNothing;
|
||||
}
|
||||
|
||||
// ADMIN FUNCTIONS.
|
||||
// Permission is checked by the calling function.
|
||||
// MODERATOR FUNCTIONS.
|
||||
// May be called by admins and moderators. Permission is checked by the calling function.
|
||||
|
||||
ResponseCode ServerSocketInterface::cmdUpdateServerMessage(Command_UpdateServerMessage * /*cmd*/, CommandContainer * /*cont*/)
|
||||
{
|
||||
|
|
@ -464,6 +470,15 @@ ResponseCode ServerSocketInterface::cmdUpdateServerMessage(Command_UpdateServerM
|
|||
return RespOk;
|
||||
}
|
||||
|
||||
// ADMIN FUNCTIONS.
|
||||
// Permission is checked by the calling function.
|
||||
|
||||
ResponseCode ServerSocketInterface::cmdShutdownServer(Command_ShutdownServer *cmd, CommandContainer * /*cont*/)
|
||||
{
|
||||
servatrice->scheduleShutdown(cmd->getReason(), cmd->getMinutes());
|
||||
return RespOk;
|
||||
}
|
||||
|
||||
ResponseCode ServerSocketInterface::cmdBanFromServer(Command_BanFromServer *cmd, CommandContainer * /*cont*/)
|
||||
{
|
||||
QString userName = cmd->getUserName();
|
||||
|
|
@ -475,14 +490,14 @@ ResponseCode ServerSocketInterface::cmdBanFromServer(Command_BanFromServer *cmd,
|
|||
ServerSocketInterface *user = static_cast<ServerSocketInterface *>(server->getUsers().value(userName));
|
||||
if (user->getUserInfo()->getUserLevel() & ServerInfo_User::IsRegistered) {
|
||||
// Registered users can be banned by name.
|
||||
if (minutes == 0) {
|
||||
QMutexLocker locker(&servatrice->dbMutex);
|
||||
QSqlQuery query;
|
||||
query.prepare("update " + servatrice->getDbPrefix() + "_users set banned=1 where name = :name");
|
||||
query.bindValue(":name", userName);
|
||||
servatrice->execSqlQuery(query);
|
||||
} else
|
||||
servatrice->addNameBan(userName, minutes);
|
||||
QMutexLocker locker(&servatrice->dbMutex);
|
||||
QSqlQuery query;
|
||||
query.prepare("insert into " + servatrice->getDbPrefix() + "_bans (id_user, id_admin, time_from, minutes, reason) values(:id_user, :id_admin, NOW(), :minutes, :reason)");
|
||||
query.bindValue(":id_user", getUserIdInDB(userName));
|
||||
query.bindValue(":id_admin", getUserIdInDB(userInfo->getName()));
|
||||
query.bindValue(":minutes", minutes);
|
||||
query.bindValue(":reason", cmd->getReason() + "\n");
|
||||
servatrice->execSqlQuery(query);
|
||||
} else {
|
||||
// Unregistered users must be banned by IP address.
|
||||
// Indefinite address bans are not reasonable -> default to 30 minutes.
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ private:
|
|||
QXmlStreamReader *xmlReader;
|
||||
QString xmlBuffer;
|
||||
TopLevelProtocolItem *topLevelItem;
|
||||
bool compressionSupport;
|
||||
int getUserIdInDB(const QString &name) const;
|
||||
|
||||
ResponseCode cmdAddToList(Command_AddToList *cmd, CommandContainer *cont);
|
||||
|
|
@ -66,8 +67,11 @@ private:
|
|||
ResponseCode cmdDeckUpload(Command_DeckUpload *cmd, CommandContainer *cont);
|
||||
DeckList *getDeckFromDatabase(int deckId);
|
||||
ResponseCode cmdDeckDownload(Command_DeckDownload *cmd, CommandContainer *cont);
|
||||
ResponseCode cmdUpdateServerMessage(Command_UpdateServerMessage *cmd, CommandContainer *cont);
|
||||
ResponseCode cmdBanFromServer(Command_BanFromServer *cmd, CommandContainer *cont);
|
||||
ResponseCode cmdShutdownServer(Command_ShutdownServer *cmd, CommandContainer *cont);
|
||||
ResponseCode cmdUpdateServerMessage(Command_UpdateServerMessage *cmd, CommandContainer *cont);
|
||||
protected:
|
||||
bool getCompressionSupport() const { return compressionSupport; }
|
||||
public:
|
||||
ServerSocketInterface(Servatrice *_server, QTcpSocket *_socket, QObject *parent = 0);
|
||||
~ServerSocketInterface();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue