Updated server and client ping to 5 seconds. Also changed hard set 1 second value on the ping timers to read values from the settings cache.

This commit is contained in:
woogerboy21 2015-07-29 23:44:00 -04:00
parent 183fbd2805
commit 8c7301b19f
5 changed files with 133 additions and 122 deletions

View file

@ -1,7 +1,7 @@
#include <QTimer>
#include <QThread>
#include "remoteclient.h"
#include "settingscache.h"
#include "pending_command.h"
#include "pb/commands.pb.h"
#include "pb/session_commands.pb.h"
@ -16,8 +16,10 @@ static const unsigned int protocolVersion = 14;
RemoteClient::RemoteClient(QObject *parent)
: AbstractClient(parent), timeRunning(0), lastDataReceived(0), messageInProgress(false), handshakeStarted(false), messageLength(0)
{
int keepalive = settingsCache->getKeepAlive();
timer = new QTimer(this);
timer->setInterval(1000);
timer->setInterval(keepalive * 1000);
connect(timer, SIGNAL(timeout()), this, SLOT(ping()));
socket = new QTcpSocket(this);
@ -102,11 +104,11 @@ void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentifica
void RemoteClient::doLogin()
{
setStatus(StatusLoggingIn);
Command_Login cmdLogin;
cmdLogin.set_user_name(userName.toStdString());
cmdLogin.set_password(password.toStdString());
PendingCommand *pend = prepareSessionCommand(cmdLogin);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(loginResponse(Response)));
sendCommand(pend);
@ -123,12 +125,12 @@ void RemoteClient::loginResponse(const Response &response)
if (response.response_code() == Response::RespOk) {
setStatus(StatusLoggedIn);
emit userInfoChanged(resp.user_info());
QList<ServerInfo_User> buddyList;
for (int i = resp.buddy_list_size() - 1; i >= 0; --i)
buddyList.append(resp.buddy_list(i));
emit buddyListReceived(buddyList);
QList<ServerInfo_User> ignoreList;
for (int i = resp.ignore_list_size() - 1; i >= 0; --i)
ignoreList.append(resp.ignore_list(i));
@ -177,7 +179,7 @@ void RemoteClient::readData()
QByteArray data = socket->readAll();
inputBuffer.append(data);
do {
if (!messageInProgress) {
if (inputBuffer.size() >= 4) {
@ -202,7 +204,7 @@ void RemoteClient::readData()
}
if (inputBuffer.size() < messageLength)
return;
ServerMessage newServerMessage;
newServerMessage.ParseFromArray(inputBuffer.data(), messageLength);
#ifdef QT_DEBUG
@ -210,9 +212,9 @@ void RemoteClient::readData()
#endif
inputBuffer.remove(0, messageLength);
messageInProgress = false;
processProtocolItem(newServerMessage);
if (getStatus() == StatusDisconnecting) // use thread-safe getter
doDisconnectFromServer();
} while (!inputBuffer.isEmpty());
@ -231,14 +233,14 @@ void RemoteClient::sendCommandContainer(const CommandContainer &cont)
buf.data()[2] = (unsigned char) (size >> 8);
buf.data()[1] = (unsigned char) (size >> 16);
buf.data()[0] = (unsigned char) (size >> 24);
socket->write(buf);
}
void RemoteClient::doConnectToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password)
{
doDisconnectFromServer();
userName = _userName;
password = _password;
lastHostname = hostname;
@ -251,7 +253,7 @@ void RemoteClient::doConnectToServer(const QString &hostname, unsigned int port,
void RemoteClient::doRegisterToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password, const QString &_email, const int _gender, const QString &_country, const QString &_realname)
{
doDisconnectFromServer();
userName = _userName;
password = _password;
email = _email;
@ -268,7 +270,7 @@ void RemoteClient::doRegisterToServer(const QString &hostname, unsigned int port
void RemoteClient::doActivateToServer(const QString &_token)
{
doDisconnectFromServer();
token = _token;
socket->connectToHost(lastHostname, lastPort);
@ -278,7 +280,7 @@ void RemoteClient::doActivateToServer(const QString &_token)
void RemoteClient::doDisconnectFromServer()
{
timer->stop();
messageInProgress = false;
handshakeStarted = false;
messageLength = 0;
@ -289,7 +291,7 @@ void RemoteClient::doDisconnectFromServer()
response.set_response_code(Response::RespNotConnected);
response.set_cmd_id(pc[i]->getCommandContainer().cmd_id());
pc[i]->processResponse(response);
delete pc[i];
}
pendingCommands.clear();
@ -309,9 +311,10 @@ void RemoteClient::ping()
}
}
int keepalive = settingsCache->getKeepAlive();
int maxTime = timeRunning - lastDataReceived;
emit maxPingTime(maxTime, maxTimeout);
if (maxTime >= maxTimeout) {
if (maxTime >= (keepalive * maxTimeout)) {
disconnectFromServer();
emit serverTimeout();
} else {

View file

@ -6,6 +6,7 @@ SettingsCache::SettingsCache()
settings = new QSettings(this);
lang = settings->value("personal/lang").toString();
keepalive = settings->value("personal/keepalive", 5).toInt();
deckPath = settings->value("paths/decks").toString();
replaysPath = settings->value("paths/replays").toString();
@ -429,7 +430,7 @@ QStringList SettingsCache::getCountries() const
<< "ad" << "ae" << "af" << "ag" << "ai" << "al" << "am" << "ao" << "aq" << "ar"
<< "as" << "at" << "au" << "aw" << "ax" << "az" << "ba" << "bb" << "bd" << "be"
<< "bf" << "bg" << "bh" << "bi" << "bj" << "bl" << "bm" << "bn" << "bo" << "bq"
<< "br" << "bs" << "bt" << "bv" << "bw" << "by" << "bz" << "ca" << "cc" << "cd"
<< "br" << "bs" << "bt" << "bv" << "bw" << "by" << "bz" << "ca" << "cc" << "cd"
<< "cf" << "cg" << "ch" << "ci" << "ck" << "cl" << "cm" << "cn" << "co" << "cr"
<< "cu" << "cv" << "cw" << "cx" << "cy" << "cz" << "de" << "dj" << "dk" << "dm"
<< "do" << "dz" << "ec" << "ee" << "eg" << "eh" << "er" << "es" << "et" << "fi"
@ -440,10 +441,10 @@ QStringList SettingsCache::getCountries() const
<< "je" << "jm" << "jo" << "jp" << "ke" << "kg" << "kh" << "ki" << "km" << "kn"
<< "kp" << "kr" << "kw" << "ky" << "kz" << "la" << "lb" << "lc" << "li" << "lk"
<< "lr" << "ls" << "lt" << "lu" << "lv" << "ly" << "ma" << "mc" << "md" << "me"
<< "mf" << "mg" << "mh" << "mk" << "ml" << "mm" << "mn" << "mo" << "mp" << "mq"
<< "mf" << "mg" << "mh" << "mk" << "ml" << "mm" << "mn" << "mo" << "mp" << "mq"
<< "mr" << "ms" << "mt" << "mu" << "mv" << "mw" << "mx" << "my" << "mz" << "na"
<< "nc" << "ne" << "nf" << "ng" << "ni" << "nl" << "no" << "np" << "nr" << "nu"
<< "nz" << "om" << "pa" << "pe" << "pf" << "pg" << "ph" << "pk" << "pl" << "pm"
<< "nz" << "om" << "pa" << "pe" << "pf" << "pg" << "ph" << "pk" << "pl" << "pm"
<< "pn" << "pr" << "ps" << "pt" << "pw" << "py" << "qa" << "re" << "ro" << "rs"
<< "ru" << "rw" << "sa" << "sb" << "sc" << "sd" << "se" << "sg" << "sh" << "si"
<< "sj" << "sk" << "sl" << "sm" << "sn" << "so" << "sr" << "ss" << "st" << "sv"
@ -507,4 +508,4 @@ void SettingsCache::setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEv
{
spectatorsCanSeeEverything = _spectatorsCanSeeEverything;
settings->setValue("game/spectatorscanseeeverything", spectatorsCanSeeEverything);
}
}

View file

@ -97,6 +97,7 @@ private:
bool spectatorsNeedPassword;
bool spectatorsCanTalk;
bool spectatorsCanSeeEverything;
int keepalive;
public:
SettingsCache();
const QByteArray &getMainWindowGeometry() const { return mainWindowGeometry; }
@ -167,6 +168,7 @@ public:
bool getSpectatorsNeedPassword() const { return spectatorsNeedPassword; }
bool getSpectatorsCanTalk() const { return spectatorsCanTalk; }
bool getSpectatorsCanSeeEverything() const { return spectatorsCanSeeEverything; }
int getKeepAlive() const { return keepalive; }
public slots:
void setMainWindowGeometry(const QByteArray &_mainWindowGeometry);
void setLang(const QString &_lang);

View file

@ -38,6 +38,14 @@ logfile=server.log
; it won't be logged. Default is empty; example: "kittens,ponies,faires"
logfilters=""
; Set the time interval in seconds that servatrice will use to communicate with each connected client
; to verify the client has not timed out. Defaults is 5 seconds
clientkeepalive=5
; Maximum time in seconds a player can stay inactive with there client not even responding to pings, before is
; considered disconnected; default is 15
max_player_inactivity_time=15
[authentication]
@ -83,8 +91,8 @@ allowpunctuationprefix=false
; Enable this feature? Default false.
;enabled=false
; Require users to provide an email address in order to register. Newly registered users will receive an
; activation token by email, and will be required to input back this token on cockatrice at the first login
; Require users to provide an email address in order to register. Newly registered users will receive an
; activation token by email, and will be required to input back this token on cockatrice at the first login
; to get their account activated. Default true.
;requireemail=true
@ -119,7 +127,7 @@ subject="Cockatrice server account activation token"
; Email body. You can use these tags here: %username %token
; They will be substituted with the actual values in the email
;
;
body="Hi %username, thank our for registering on our Cockatrice server\r\nHere's the activation token you need to supply for activating your account:\r\n\r\n%token\r\n\r\nHappy gaming!"
[database]
@ -178,10 +186,6 @@ roomlist\1\game_types\3\name="GameType3"
[game]
; Maximum time in seconds a player can stay inactive, with his client hot even responding to pings, before is
; considered disconnected; default is 15
max_player_inactivity_time=15
; Maximum time in seconds all players in a game can stay inactive before the game is automatically closed;
; default is 120
max_game_inactivity_time=120

View file

@ -161,13 +161,13 @@ bool Servatrice::initServer()
authenticationMethod = AuthenticationNone;
}
bool maxUserLimitEnabled = settingsCache->value("security/enable_max_user_limit", false).toBool();
qDebug() << "Maximum user limit enabled: " << maxUserLimitEnabled;
bool maxUserLimitEnabled = settingsCache->value("security/enable_max_user_limit", false).toBool();
qDebug() << "Maximum user limit enabled: " << maxUserLimitEnabled;
if (maxUserLimitEnabled){
int maxUserLimit = settingsCache->value("security/max_users_total", 500).toInt();
qDebug() << "Maximum user limit: " << maxUserLimit;
}
if (maxUserLimitEnabled){
int maxUserLimit = settingsCache->value("security/max_users_total", 500).toInt();
qDebug() << "Maximum user limit: " << maxUserLimit;
}
bool registrationEnabled = settingsCache->value("registration/enabled", false).toBool();
bool requireEmailForRegistration = settingsCache->value("registration/requireemail", true).toBool();
@ -273,7 +273,7 @@ bool Servatrice::initServer()
updateLoginMessage();
maxGameInactivityTime = settingsCache->value("game/max_game_inactivity_time", 120).toInt();
maxPlayerInactivityTime = settingsCache->value("game/max_player_inactivity_time", 15).toInt();
maxPlayerInactivityTime = settingsCache->value("server/max_player_inactivity_time", 15).toInt();
maxUsersPerAddress = settingsCache->value("security/max_users_per_address", 4).toInt();
messageCountingInterval = settingsCache->value("security/message_counting_interval", 10).toInt();
@ -283,90 +283,91 @@ bool Servatrice::initServer()
commandCountingInterval = settingsCache->value("game/command_counting_interval", 10).toInt();
maxCommandCountPerInterval = settingsCache->value("game/max_command_count_per_interval", 20).toInt();
try { if (settingsCache->value("servernetwork/active", 0).toInt()) {
qDebug() << "Connecting to ISL network.";
const QString certFileName = settingsCache->value("servernetwork/ssl_cert").toString();
const QString keyFileName = settingsCache->value("servernetwork/ssl_key").toString();
qDebug() << "Loading certificate...";
QFile certFile(certFileName);
if (!certFile.open(QIODevice::ReadOnly))
throw QString("Error opening certificate file: %1").arg(certFileName);
QSslCertificate cert(&certFile);
try { if (settingsCache->value("servernetwork/active", 0).toInt()) {
qDebug() << "Connecting to ISL network.";
const QString certFileName = settingsCache->value("servernetwork/ssl_cert").toString();
const QString keyFileName = settingsCache->value("servernetwork/ssl_key").toString();
qDebug() << "Loading certificate...";
QFile certFile(certFileName);
if (!certFile.open(QIODevice::ReadOnly))
throw QString("Error opening certificate file: %1").arg(certFileName);
QSslCertificate cert(&certFile);
#if QT_VERSION < 0x050000
if (!cert.isValid())
throw(QString("Invalid certificate."));
if (!cert.isValid())
throw(QString("Invalid certificate."));
#else
const QDateTime currentTime = QDateTime::currentDateTime();
if(currentTime < cert.effectiveDate() ||
currentTime > cert.expiryDate() ||
cert.isBlacklisted())
throw(QString("Invalid certificate."));
const QDateTime currentTime = QDateTime::currentDateTime();
if(currentTime < cert.effectiveDate() ||
currentTime > cert.expiryDate() ||
cert.isBlacklisted())
throw(QString("Invalid certificate."));
#endif
qDebug() << "Loading private key...";
QFile keyFile(keyFileName);
if (!keyFile.open(QIODevice::ReadOnly))
throw QString("Error opening private key file: %1").arg(keyFileName);
QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
if (key.isNull())
throw QString("Invalid private key.");
qDebug() << "Loading private key...";
QFile keyFile(keyFileName);
if (!keyFile.open(QIODevice::ReadOnly))
throw QString("Error opening private key file: %1").arg(keyFileName);
QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
if (key.isNull())
throw QString("Invalid private key.");
QMutableListIterator<ServerProperties> serverIterator(serverList);
while (serverIterator.hasNext()) {
const ServerProperties &prop = serverIterator.next();
if (prop.cert == cert) {
serverIterator.remove();
continue;
}
QMutableListIterator<ServerProperties> serverIterator(serverList);
while (serverIterator.hasNext()) {
const ServerProperties &prop = serverIterator.next();
if (prop.cert == cert) {
serverIterator.remove();
continue;
}
QThread *thread = new QThread;
thread->setObjectName("isl_" + QString::number(prop.id));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
QThread *thread = new QThread;
thread->setObjectName("isl_" + QString::number(prop.id));
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);
interface->moveToThread(thread);
connect(interface, SIGNAL(destroyed()), thread, SLOT(quit()));
IslInterface *interface = new IslInterface(prop.id, prop.hostname, prop.address.toString(), prop.controlPort, prop.cert, cert, key, this);
interface->moveToThread(thread);
connect(interface, SIGNAL(destroyed()), thread, SLOT(quit()));
thread->start();
QMetaObject::invokeMethod(interface, "initClient", Qt::BlockingQueuedConnection);
}
thread->start();
QMetaObject::invokeMethod(interface, "initClient", Qt::BlockingQueuedConnection);
}
const int networkPort = settingsCache->value("servernetwork/port", 14747).toInt();
qDebug() << "Starting ISL server on port" << networkPort;
const int networkPort = settingsCache->value("servernetwork/port", 14747).toInt();
qDebug() << "Starting ISL server on port" << networkPort;
islServer = new Servatrice_IslServer(this, cert, key, this);
if (islServer->listen(QHostAddress::Any, networkPort))
qDebug() << "ISL server listening.";
else
throw QString("islServer->listen()");
} } catch (QString error) {
qDebug() << "ERROR --" << error;
return false;
}
islServer = new Servatrice_IslServer(this, cert, key, this);
if (islServer->listen(QHostAddress::Any, networkPort))
qDebug() << "ISL server listening.";
else
throw QString("islServer->listen()");
} } catch (QString error) {
qDebug() << "ERROR --" << error;
return false;
}
pingClock = new QTimer(this);
connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout()));
pingClock->start(1000);
int clientkeepalive = settingsCache->value("server/clientkeepalive", 1).toInt();
pingClock = new QTimer(this);
connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout()));
pingClock->start(clientkeepalive * 1000);
int statusUpdateTime = settingsCache->value("server/statusupdate", 15000).toInt();
statusUpdateClock = new QTimer(this);
connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate()));
if (statusUpdateTime != 0) {
qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms";
statusUpdateClock->start(statusUpdateTime);
}
int statusUpdateTime = settingsCache->value("server/statusupdate", 15000).toInt();
statusUpdateClock = new QTimer(this);
connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate()));
if (statusUpdateTime != 0) {
qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms";
statusUpdateClock->start(statusUpdateTime);
}
const int numberPools = settingsCache->value("server/number_pools", 1).toInt();
gameServer = new Servatrice_GameServer(this, numberPools, servatriceDatabaseInterface->getDatabase(), this);
gameServer->setMaxPendingConnections(1000);
const int gamePort = settingsCache->value("server/port", 4747).toInt();
qDebug() << "Starting server on port" << gamePort;
if (gameServer->listen(QHostAddress::Any, gamePort))
qDebug() << "Server listening.";
else {
qDebug() << "gameServer->listen(): Error:" << gameServer->errorString();
return false;
}
return true;
const int numberPools = settingsCache->value("server/number_pools", 1).toInt();
gameServer = new Servatrice_GameServer(this, numberPools, servatriceDatabaseInterface->getDatabase(), this);
gameServer->setMaxPendingConnections(1000);
const int gamePort = settingsCache->value("server/port", 4747).toInt();
qDebug() << "Starting server on port" << gamePort;
if (gameServer->listen(QHostAddress::Any, gamePort))
qDebug() << "Server listening.";
else {
qDebug() << "gameServer->listen(): Error:" << gameServer->errorString();
return false;
}
return true;
}
void Servatrice::addDatabaseInterface(QThread *thread, Servatrice_DatabaseInterface *databaseInterface)
@ -376,20 +377,20 @@ void Servatrice::addDatabaseInterface(QThread *thread, Servatrice_DatabaseInterf
void Servatrice::updateServerList()
{
qDebug() << "Updating server list...";
qDebug() << "Updating server list...";
serverListMutex.lock();
serverList.clear();
serverListMutex.lock();
serverList.clear();
QSqlQuery *query = servatriceDatabaseInterface->prepareQuery("select id, ssl_cert, hostname, address, game_port, control_port from {prefix}_servers order by id asc");
servatriceDatabaseInterface->execSqlQuery(query);
while (query->next()) {
ServerProperties prop(query->value(0).toInt(), QSslCertificate(query->value(1).toString().toUtf8()), query->value(2).toString(), QHostAddress(query->value(3).toString()), query->value(4).toInt(), query->value(5).toInt());
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);
}
QSqlQuery *query = servatriceDatabaseInterface->prepareQuery("select id, ssl_cert, hostname, address, game_port, control_port from {prefix}_servers order by id asc");
servatriceDatabaseInterface->execSqlQuery(query);
while (query->next()) {
ServerProperties prop(query->value(0).toInt(), QSslCertificate(query->value(1).toString().toUtf8()), query->value(2).toString(), QHostAddress(query->value(3).toString()), query->value(4).toInt(), query->value(5).toInt());
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);
}
serverListMutex.unlock();
serverListMutex.unlock();
}
QList<ServerProperties> Servatrice::getServerList() const
@ -408,7 +409,7 @@ int Servatrice::getUsersWithAddress(const QHostAddress &address) const
for (int i = 0; i < clients.size(); ++i)
if (static_cast<ServerSocketInterface *>(clients[i])->getPeerAddress() == address)
++result;
return result;
}
@ -483,9 +484,9 @@ void Servatrice::statusUpdate()
QSqlQuery *query = servatriceDatabaseInterface->prepareQuery("select a.name, b.email, b.token from {prefix}_activation_emails a left join {prefix}_users b on a.name = b.name");
if (!servatriceDatabaseInterface->execSqlQuery(query))
return;
QSqlQuery *queryDelete = servatriceDatabaseInterface->prepareQuery("delete from {prefix}_activation_emails where name = :name");
while (query->next()) {
const QString userName = query->value(0).toString();
const QString emailAddress = query->value(1).toString();
@ -551,7 +552,7 @@ void Servatrice::shutdownTimeout()
clients[i]->sendProtocolItem(*se);
clientsLock.unlock();
delete se;
if (!shutdownMinutes)
deleteLater();
}