switched NetworkServerThread to new thread creation method, SSL is working

This commit is contained in:
Max-Wilhelm Bruker 2012-03-10 16:16:31 +01:00
parent 0719d4c6ed
commit decf1c04bd
6 changed files with 98 additions and 165 deletions

View file

@ -10,7 +10,6 @@ SET(servatrice_SOURCES
src/serversocketinterface.cpp
src/serversocketthread.cpp
src/networkserverinterface.cpp
src/networkserverthread.cpp
${CMAKE_CURRENT_BINARY_DIR}/version_string.cpp
)
SET(servatrice_HEADERS
@ -19,7 +18,6 @@ SET(servatrice_HEADERS
src/serversocketinterface.h
src/serversocketthread.h
src/networkserverinterface.h
src/networkserverthread.h
)
SET(QT_DONTUSE_QTGUI)

View file

@ -9,17 +9,75 @@
#include "pb/event_server_complete_list.pb.h"
#include <google/protobuf/descriptor.h>
void NetworkServerInterface::sharedCtor()
void NetworkServerInterface::sharedCtor(const QSslCertificate &cert, const QSslKey &privateKey)
{
socket = new QSslSocket(this);
socket->setLocalCertificate(cert);
socket->setPrivateKey(privateKey);
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)
NetworkServerInterface::NetworkServerInterface(int _socketDescriptor, const QSslCertificate &cert, const QSslKey &privateKey, Servatrice *_server)
: QObject(), socketDescriptor(_socketDescriptor), server(_server), messageInProgress(false)
{
sharedCtor(cert, privateKey);
}
NetworkServerInterface::NetworkServerInterface(const QString &_peerHostName, const QString &_peerAddress, int _peerPort, const QSslCertificate &_peerCert, const QSslCertificate &cert, const QSslKey &privateKey, Servatrice *_server)
: QObject(), peerHostName(_peerHostName), peerAddress(_peerAddress), peerPort(_peerPort), peerCert(_peerCert), server(_server), messageInProgress(false)
{
sharedCtor(cert, privateKey);
}
NetworkServerInterface::~NetworkServerInterface()
{
logger->logMessage("[SN] session ended", this);
flushOutputBuffer();
}
void NetworkServerInterface::initServer()
{
socket->setSocketDescriptor(socketDescriptor);
logger->logMessage(QString("[SN] incoming connection: %1").arg(socket->peerAddress().toString()));
QList<ServerProperties> serverList = server->getServerList();
int listIndex = -1;
for (int i = 0; i < serverList.size(); ++i)
if (serverList[i].address == socket->peerAddress()) {
listIndex = i;
break;
}
if (listIndex == -1) {
logger->logMessage(QString("[SN] address %1 unknown, terminating connection").arg(socket->peerAddress().toString()));
deleteLater();
return;
}
socket->startServerEncryption();
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;
}
if (serverList[listIndex].cert == socket->peerCertificate())
logger->logMessage(QString("[SN] Peer authenticated as " + serverList[listIndex].hostname));
else {
logger->logMessage(QString("[SN] Authentication failed, terminating connection"));
deleteLater();
return;
}
Event_ServerCompleteList event;
event.set_server_id(server->getServerId());
@ -49,11 +107,14 @@ 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)
void NetworkServerInterface::initClient()
{
sharedCtor();
QList<QSslError> expectedErrors;
expectedErrors.append(QSslError(QSslError::SelfSignedCertificate, peerCert));
socket->ignoreSslErrors(expectedErrors);
qDebug() << "[SN] Connecting to " << peerAddress << ":" << peerPort;
socket->connectToHostEncrypted(peerAddress, peerPort, peerHostName);
if (!socket->waitForConnected(5000)) {
qDebug() << "[SN] Socket error:" << socket->errorString();
@ -72,17 +133,9 @@ NetworkServerInterface::NetworkServerInterface(const QString &peerHostName, cons
server->addNetworkServerInterface(this);
}
NetworkServerInterface::~NetworkServerInterface()
{
logger->logMessage("[SN] session ended", this);
flushOutputBuffer();
}
void NetworkServerInterface::flushOutputBuffer()
{
QMutexLocker locker(&outputBufferMutex);
qDebug("FLUSH");
if (outputBuffer.isEmpty())
return;
server->incTxBytes(outputBuffer.size());
@ -142,7 +195,6 @@ void NetworkServerInterface::transmitMessage(const ServerNetworkMessage &item)
outputBufferMutex.lock();
outputBuffer.append(buf);
outputBufferMutex.unlock();
qDebug("TRANSMIT");
emit outputBufferChanged();
}

View file

@ -2,6 +2,9 @@
#define NETWORKSERVERINTERFACE_H
#include "servatrice.h"
#include <QSslCertificate>
#include <QSslKey>
#include <QWaitCondition>
class Servatrice;
class QSslSocket;
@ -16,6 +19,11 @@ private slots:
signals:
void outputBufferChanged();
private:
int socketDescriptor;
QString peerHostName, peerAddress;
int peerPort;
QSslCertificate peerCert;
QMutex outputBufferMutex;
Servatrice *server;
QSslSocket *socket;
@ -25,10 +33,13 @@ private:
int messageLength;
void processMessage(const ServerNetworkMessage &item);
void sharedCtor();
void sharedCtor(const QSslCertificate &cert, const QSslKey &privateKey);
public slots:
void initServer();
void initClient();
public:
NetworkServerInterface(Servatrice *_server, QSslSocket *_socket);
NetworkServerInterface(const QString &peerHostName, const QString &peerAddress, int peerPort, Servatrice *_server, QSslSocket *_socket);
NetworkServerInterface(int socketDescriptor, const QSslCertificate &cert, const QSslKey &privateKey, Servatrice *_server);
NetworkServerInterface(const QString &peerHostName, const QString &peerAddress, int peerPort, const QSslCertificate &peerCert, const QSslCertificate &cert, const QSslKey &privateKey, Servatrice *_server);
~NetworkServerInterface();
void transmitMessage(const ServerNetworkMessage &item);

View file

@ -1,100 +0,0 @@
#include "networkserverthread.h"
#include "networkserverinterface.h"
#include "server_logger.h"
#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), 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()));
}
NetworkServerThread::~NetworkServerThread()
{
quit();
wait();
delete socket;
}
void NetworkServerThread::run()
{
socket = new QSslSocket;
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();
int listIndex = -1;
for (int i = 0; i < serverList.size(); ++i)
if (serverList[i].address == socket->peerAddress()) {
listIndex = i;
break;
}
if (listIndex == -1) {
logger->logMessage(QString("[SN] address %1 unknown, terminating connection").arg(socket->peerAddress().toString()));
return;
}
socket->startServerEncryption();
if (!socket->waitForEncrypted(5000)) {
logger->logMessage(QString("[SN] SSL handshake timeout, terminating connection"));
return;
}
if (serverList[listIndex].cert == socket->peerCertificate())
logger->logMessage(QString("[SN] Peer authenticated as " + serverList[listIndex].hostname));
else {
logger->logMessage(QString("[SN] Authentication failed, terminating connection"));
return;
}
}
void NetworkServerThread::initClient()
{
qDebug() << "[SN] Connecting to " << peerAddress << ":" << peerPort;
QList<QSslError> expectedErrors;
expectedErrors.append(QSslError(QSslError::SelfSignedCertificate, peerCert));
socket->ignoreSslErrors(expectedErrors);
}

View file

@ -1,38 +0,0 @@
#ifndef NETWORKSERVERTHREAD_H
#define NETWORKSERVERTHREAD_H
#include <QThread>
#include <QSslCertificate>
#include <QSslKey>
#include <QWaitCondition>
class Servatrice;
class NetworkServerInterface;
class QSslSocket;
class NetworkServerThread : public QThread {
Q_OBJECT
private:
Servatrice *server;
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();
};
#endif

View file

@ -25,7 +25,7 @@
#include "server_room.h"
#include "serversocketinterface.h"
#include "serversocketthread.h"
#include "networkserverthread.h"
#include "networkserverinterface.h"
#include "server_logger.h"
#include "main.h"
#include "passwordhasher.h"
@ -50,8 +50,15 @@ void Servatrice_GameServer::incomingConnection(int socketDescriptor)
void Servatrice_NetworkServer::incomingConnection(int socketDescriptor)
{
NetworkServerThread *thread = new NetworkServerThread(socketDescriptor, server, cert, privateKey);
QThread *thread = new QThread;
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
NetworkServerInterface *interface = new NetworkServerInterface(socketDescriptor, cert, privateKey, server);
interface->moveToThread(thread);
connect(interface, SIGNAL(destroyed()), thread, SLOT(quit()));
thread->start();
QMetaObject::invokeMethod(interface, "initServer", Qt::QueuedConnection);
}
Servatrice::Servatrice(QSettings *_settings, QObject *parent)
@ -150,12 +157,15 @@ Servatrice::Servatrice(QSettings *_settings, QObject *parent)
continue;
}
NetworkServerThread *thread = new NetworkServerThread(prop.hostname, prop.address.toString(), prop.controlPort, prop.cert, this, cert, key);
thread->start();
QThread *thread = new QThread;
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
QMutex initMutex;
initMutex.lock();
thread->initWaitCondition.wait(&initMutex);
NetworkServerInterface *interface = new NetworkServerInterface(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);
}
} } catch (QString error) {