client-side SSL works, thread initialization needs fixing
This commit is contained in:
parent
c9b66e4239
commit
0719d4c6ed
5 changed files with 164 additions and 63 deletions
|
@ -9,14 +9,17 @@
|
|||
#include "pb/event_server_complete_list.pb.h"
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
NetworkServerInterface::NetworkServerInterface(Servatrice *_server, QSslSocket *_socket)
|
||||
: QObject(), server(_server), socket(_socket), messageInProgress(false)
|
||||
void NetworkServerInterface::sharedCtor()
|
||||
{
|
||||
connect(socket, SIGNAL(readyRead()), this, SLOT(readClient()));
|
||||
connect(socket, SIGNAL(disconnected()), this, SLOT(deleteLater()));
|
||||
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(catchSocketError(QAbstractSocket::SocketError)));
|
||||
connect(this, SIGNAL(outputBufferChanged()), this, SLOT(flushOutputBuffer()), Qt::QueuedConnection);
|
||||
|
||||
}
|
||||
|
||||
NetworkServerInterface::NetworkServerInterface(Servatrice *_server, QSslSocket *_socket)
|
||||
: QObject(), server(_server), socket(_socket), messageInProgress(false)
|
||||
{
|
||||
Event_ServerCompleteList event;
|
||||
event.set_server_id(server->getServerId());
|
||||
|
||||
|
@ -46,6 +49,29 @@ NetworkServerInterface::NetworkServerInterface(Servatrice *_server, QSslSocket *
|
|||
server->serverMutex.unlock();
|
||||
}
|
||||
|
||||
NetworkServerInterface::NetworkServerInterface(const QString &peerHostName, const QString &peerAddress, int peerPort, Servatrice *_server, QSslSocket *_socket)
|
||||
: QObject(), server(_server), socket(_socket), messageInProgress(false)
|
||||
{
|
||||
sharedCtor();
|
||||
|
||||
socket->connectToHostEncrypted(peerAddress, peerPort, peerHostName);
|
||||
if (!socket->waitForConnected(5000)) {
|
||||
qDebug() << "[SN] Socket error:" << socket->errorString();
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
if (!socket->waitForEncrypted(5000)) {
|
||||
QList<QSslError> sslErrors(socket->sslErrors());
|
||||
if (sslErrors.isEmpty())
|
||||
qDebug() << "[SN] SSL handshake timeout, terminating connection";
|
||||
else
|
||||
qDebug() << "[SN] SSL errors:" << sslErrors;
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
server->addNetworkServerInterface(this);
|
||||
}
|
||||
|
||||
NetworkServerInterface::~NetworkServerInterface()
|
||||
{
|
||||
logger->logMessage("[SN] session ended", this);
|
||||
|
@ -56,6 +82,7 @@ NetworkServerInterface::~NetworkServerInterface()
|
|||
void NetworkServerInterface::flushOutputBuffer()
|
||||
{
|
||||
QMutexLocker locker(&outputBufferMutex);
|
||||
qDebug("FLUSH");
|
||||
if (outputBuffer.isEmpty())
|
||||
return;
|
||||
server->incTxBytes(outputBuffer.size());
|
||||
|
@ -96,7 +123,7 @@ void NetworkServerInterface::readClient()
|
|||
|
||||
void NetworkServerInterface::catchSocketError(QAbstractSocket::SocketError socketError)
|
||||
{
|
||||
qDebug() << "Socket error:" << socketError;
|
||||
qDebug() << "[SN] Socket error:" << socketError;
|
||||
|
||||
deleteLater();
|
||||
}
|
||||
|
@ -112,11 +139,14 @@ void NetworkServerInterface::transmitMessage(const ServerNetworkMessage &item)
|
|||
buf.data()[1] = (unsigned char) (size >> 16);
|
||||
buf.data()[0] = (unsigned char) (size >> 24);
|
||||
|
||||
QMutexLocker locker(&outputBufferMutex);
|
||||
outputBufferMutex.lock();
|
||||
outputBuffer.append(buf);
|
||||
outputBufferMutex.unlock();
|
||||
qDebug("TRANSMIT");
|
||||
emit outputBufferChanged();
|
||||
}
|
||||
|
||||
void NetworkServerInterface::processMessage(const ServerNetworkMessage &item)
|
||||
{
|
||||
qDebug() << QString::fromStdString(item.DebugString());
|
||||
}
|
||||
|
|
|
@ -25,8 +25,10 @@ private:
|
|||
int messageLength;
|
||||
|
||||
void processMessage(const ServerNetworkMessage &item);
|
||||
void sharedCtor();
|
||||
public:
|
||||
NetworkServerInterface(Servatrice *_server, QSslSocket *_socket);
|
||||
NetworkServerInterface(const QString &peerHostName, const QString &peerAddress, int peerPort, Servatrice *_server, QSslSocket *_socket);
|
||||
~NetworkServerInterface();
|
||||
|
||||
void transmitMessage(const ServerNetworkMessage &item);
|
||||
|
|
|
@ -4,9 +4,16 @@
|
|||
#include "servatrice.h"
|
||||
#include "main.h"
|
||||
#include <QSslSocket>
|
||||
#include <QSslError>
|
||||
|
||||
NetworkServerThread::NetworkServerThread(int _socketDescriptor, Servatrice *_server, const QSslCertificate &_cert, const QSslKey &_privateKey, QObject *parent)
|
||||
: QThread(parent), server(_server), socketDescriptor(_socketDescriptor), cert(_cert), privateKey(_privateKey)
|
||||
: QThread(parent), server(_server), socketDescriptor(_socketDescriptor), cert(_cert), privateKey(_privateKey), connectionType(ServerType)
|
||||
{
|
||||
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
|
||||
}
|
||||
|
||||
NetworkServerThread::NetworkServerThread(const QString &_hostName, const QString &_address, int _port, const QSslCertificate &_peerCert, Servatrice *_server, const QSslCertificate &_cert, const QSslKey &_privateKey, QObject *parent)
|
||||
: QThread(parent), server(_server), cert(_cert), privateKey(_privateKey), peerHostName(_hostName), peerAddress(_address), peerPort(_port), peerCert(_peerCert), connectionType(ClientType)
|
||||
{
|
||||
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
|
||||
}
|
||||
|
@ -22,10 +29,38 @@ NetworkServerThread::~NetworkServerThread()
|
|||
void NetworkServerThread::run()
|
||||
{
|
||||
socket = new QSslSocket;
|
||||
socket->setSocketDescriptor(socketDescriptor);
|
||||
socket->setLocalCertificate(cert);
|
||||
socket->setPrivateKey(privateKey);
|
||||
|
||||
if (connectionType == ClientType)
|
||||
try {
|
||||
initClient();
|
||||
} catch (bool) {
|
||||
usleep(100000);
|
||||
initWaitCondition.wakeAll();
|
||||
return;
|
||||
}
|
||||
else
|
||||
try {
|
||||
initServer();
|
||||
} catch (bool) {
|
||||
return;
|
||||
}
|
||||
|
||||
interface = new NetworkServerInterface(server, socket);
|
||||
connect(interface, SIGNAL(destroyed()), this, SLOT(deleteLater()));
|
||||
|
||||
if (connectionType == ClientType) {
|
||||
usleep(100000);
|
||||
initWaitCondition.wakeAll();
|
||||
}
|
||||
|
||||
exec();
|
||||
}
|
||||
|
||||
void NetworkServerThread::initServer()
|
||||
{
|
||||
socket->setSocketDescriptor(socketDescriptor);
|
||||
logger->logMessage(QString("[SN] incoming connection: %1").arg(socket->peerAddress().toString()));
|
||||
|
||||
QList<ServerProperties> serverList = server->getServerList();
|
||||
|
@ -52,9 +87,14 @@ void NetworkServerThread::run()
|
|||
logger->logMessage(QString("[SN] Authentication failed, terminating connection"));
|
||||
return;
|
||||
}
|
||||
|
||||
interface = new NetworkServerInterface(server, socket);
|
||||
connect(interface, SIGNAL(destroyed()), this, SLOT(deleteLater()));
|
||||
|
||||
exec();
|
||||
}
|
||||
|
||||
void NetworkServerThread::initClient()
|
||||
{
|
||||
qDebug() << "[SN] Connecting to " << peerAddress << ":" << peerPort;
|
||||
|
||||
QList<QSslError> expectedErrors;
|
||||
expectedErrors.append(QSslError(QSslError::SelfSignedCertificate, peerCert));
|
||||
socket->ignoreSslErrors(expectedErrors);
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <QThread>
|
||||
#include <QSslCertificate>
|
||||
#include <QSslKey>
|
||||
#include <QWaitCondition>
|
||||
|
||||
class Servatrice;
|
||||
class NetworkServerInterface;
|
||||
|
@ -16,11 +17,20 @@ private:
|
|||
NetworkServerInterface *interface;
|
||||
QSslCertificate cert;
|
||||
QSslKey privateKey;
|
||||
QString peerHostName, peerAddress;
|
||||
int peerPort;
|
||||
QSslCertificate peerCert;
|
||||
int socketDescriptor;
|
||||
QSslSocket *socket;
|
||||
enum ConnectionType { ClientType, ServerType } connectionType;
|
||||
|
||||
void initClient();
|
||||
void initServer();
|
||||
public:
|
||||
NetworkServerThread(int _socketDescriptor, Servatrice *_server, const QSslCertificate &_cert, const QSslKey &_privateKey, QObject *parent = 0);
|
||||
NetworkServerThread(const QString &_hostName, const QString &_address, int _port, const QSslCertificate &peerCert, Servatrice *_server, const QSslCertificate &_cert, const QSslKey &_privateKey, QObject *parent = 0);
|
||||
~NetworkServerThread();
|
||||
QWaitCondition initWaitCondition;
|
||||
protected:
|
||||
void run();
|
||||
};
|
||||
|
|
|
@ -57,28 +57,8 @@ void Servatrice_NetworkServer::incomingConnection(int socketDescriptor)
|
|||
Servatrice::Servatrice(QSettings *_settings, QObject *parent)
|
||||
: Server(parent), dbMutex(QMutex::Recursive), settings(_settings), uptime(0), shutdownTimer(0)
|
||||
{
|
||||
pingClock = new QTimer(this);
|
||||
connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout()));
|
||||
pingClock->start(1000);
|
||||
|
||||
serverName = settings->value("server/name").toString();
|
||||
serverId = settings->value("server/id", 0).toInt();
|
||||
int statusUpdateTime = settings->value("server/statusupdate").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);
|
||||
}
|
||||
|
||||
threaded = settings->value("server/threaded", false).toInt();
|
||||
gameServer = new Servatrice_GameServer(this, threaded, this);
|
||||
const int gamePort = settings->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.";
|
||||
|
||||
const QString authenticationMethodStr = settings->value("authentication/method").toString();
|
||||
if (authenticationMethodStr == "sql")
|
||||
|
@ -98,37 +78,6 @@ Servatrice::Servatrice(QSettings *_settings, QObject *parent)
|
|||
updateServerList();
|
||||
clearSessionTables();
|
||||
|
||||
try { if (settings->value("servernetwork/active", 0).toInt()) {
|
||||
qDebug() << "Connecting to server network.";
|
||||
const QString certFileName = settings->value("servernetwork/ssl_cert").toString();
|
||||
const QString keyFileName = settings->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 (!cert.isValid())
|
||||
throw(QString("Invalid certificate."));
|
||||
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.");
|
||||
|
||||
const int networkPort = settings->value("servernetwork/port", 14747).toInt();
|
||||
qDebug() << "Starting network server on port" << networkPort;
|
||||
|
||||
networkServer = new Servatrice_NetworkServer(this, cert, key, this);
|
||||
if (networkServer->listen(QHostAddress::Any, networkPort))
|
||||
qDebug() << "Network server listening.";
|
||||
else
|
||||
throw QString("networkServer->listen(): Error.");
|
||||
} } catch (QString error) {
|
||||
qDebug() << "ERROR --" << error;
|
||||
}
|
||||
|
||||
int size = settings->beginReadArray("rooms");
|
||||
for (int i = 0; i < size; ++i) {
|
||||
settings->setArrayIndex(i);
|
||||
|
@ -164,6 +113,76 @@ Servatrice::Servatrice(QSettings *_settings, QObject *parent)
|
|||
maxMessageCountPerInterval = settings->value("security/max_message_count_per_interval").toInt();
|
||||
maxMessageSizePerInterval = settings->value("security/max_message_size_per_interval").toInt();
|
||||
maxGamesPerUser = settings->value("security/max_games_per_user").toInt();
|
||||
|
||||
try { if (settings->value("servernetwork/active", 0).toInt()) {
|
||||
qDebug() << "Connecting to server network.";
|
||||
const QString certFileName = settings->value("servernetwork/ssl_cert").toString();
|
||||
const QString keyFileName = settings->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 (!cert.isValid())
|
||||
throw(QString("Invalid certificate."));
|
||||
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.");
|
||||
|
||||
const int networkPort = settings->value("servernetwork/port", 14747).toInt();
|
||||
qDebug() << "Starting network server on port" << networkPort;
|
||||
|
||||
networkServer = new Servatrice_NetworkServer(this, cert, key, this);
|
||||
if (networkServer->listen(QHostAddress::Any, networkPort))
|
||||
qDebug() << "Network server listening.";
|
||||
else
|
||||
throw QString("networkServer->listen(): Error.");
|
||||
|
||||
QMutableListIterator<ServerProperties> serverIterator(serverList);
|
||||
while (serverIterator.hasNext()) {
|
||||
const ServerProperties &prop = serverIterator.next();
|
||||
if (prop.cert == cert) {
|
||||
serverIterator.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
NetworkServerThread *thread = new NetworkServerThread(prop.hostname, prop.address.toString(), prop.controlPort, prop.cert, this, cert, key);
|
||||
thread->start();
|
||||
|
||||
QMutex initMutex;
|
||||
initMutex.lock();
|
||||
thread->initWaitCondition.wait(&initMutex);
|
||||
}
|
||||
|
||||
} } catch (QString error) {
|
||||
qDebug() << "ERROR --" << error;
|
||||
}
|
||||
|
||||
pingClock = new QTimer(this);
|
||||
connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout()));
|
||||
pingClock->start(1000);
|
||||
|
||||
int statusUpdateTime = settings->value("server/statusupdate").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);
|
||||
}
|
||||
|
||||
threaded = settings->value("server/threaded", false).toInt();
|
||||
gameServer = new Servatrice_GameServer(this, threaded, this);
|
||||
const int gamePort = settings->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.";
|
||||
|
||||
}
|
||||
|
||||
Servatrice::~Servatrice()
|
||||
|
|
Loading…
Reference in a new issue