/*
# Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
#
# This program is free software distributed under the GPL version 2.
# See http://openslx.org/COPYING
#
# If you have any feedback please consult http://openslx.org/feedback and
# send your suggestions, praise, or complaints to feedback@openslx.org
#
# General information about OpenSLX can be found at http://openslx.org/
# -----------------------------------------------------------------------------
# src/net/pvsDiscoveredServer.cpp
# - represents an entry in the list of available servers
# - handles some extra things like validating the identity of the remote host
# -----------------------------------------------------------------------------
*/
#include "pvsDiscoveredServer.h"
#include "src/util/serviceDiscoveryUtil.h"
#include <QtNetwork/QSslKey>
PVSDiscoveredServer::PVSDiscoveredServer(QObject* parent, QHostAddress host, int port, QByteArray fingerprint, QString name)
: QObject(parent)
{
_validated = false;
_socket = NULL;
_host = host;
_port = port;
_fingerprint = fingerprint;
_name = name;
_lastUpdate = QDateTime::currentDateTime();
_lastCheck = QDateTime::fromTime_t(1000000);
this->validateCertificate();
}
PVSDiscoveredServer::~PVSDiscoveredServer() {
delete _socket;
}
void PVSDiscoveredServer::ssl_Error( const QList<QSslError> & errors )
{
for (QList<QSslError>::const_iterator it = errors.begin(); it != errors.end(); it++)
{
QSslError err = *it;
if (err.error() == QSslError::HostNameMismatch) continue; // We don't pay attention to hostnames for validation
if (err.error() == QSslError::SelfSignedCertificate) {
continue; // Also, this will always be the case; we check the fingerprint later
}
// http://doc.trolltech.com/4.7//qsslerror.html#SslError-enum
qDebug("Unhandled SSL Error %i: %s", err.error(), qPrintable(err.errorString()));
return;
}
_socket->ignoreSslErrors();
}
void PVSDiscoveredServer::sock_dataArrival()
{
if (_socket == NULL) return;
char charbuff[2000];
while (_socket->bytesAvailable())
{
_socket->read(charbuff, 2000);
}
}
void PVSDiscoveredServer::sock_connected()
{
QByteArray cert = _socket->peerCertificate().digest(QCryptographicHash::Sha1);
if (_socket->peerCertificate().isNull())
{
qDebug("**** WARNING - PEER CERTIFICATE IS NULL ****");
}
else
{
qDebug("%s", qPrintable(_socket->peerCertificate().subjectInfo(QSslCertificate::Organization)));
qDebug("%s", qPrintable(_socket->peerCertificate().subjectInfo(QSslCertificate::CommonName)));
qDebug("%s", qPrintable(_socket->peerCertificate().subjectInfo(QSslCertificate::LocalityName)));
qDebug("%s", qPrintable(_socket->peerCertificate().subjectInfo(QSslCertificate::OrganizationalUnitName)));
qDebug("%s", qPrintable(_socket->peerCertificate().subjectInfo(QSslCertificate::CountryName)));
qDebug("%s", qPrintable(_socket->peerCertificate().subjectInfo(QSslCertificate::StateOrProvinceName)));
}
if (cert == _fingerprint && !_validated)
{
_validated = true;
emit validated(this);
qDebug("Validated certificate of %s :)", qPrintable(_socket->peerAddress().toString()));
}
else
{
qDebug("Certificate of %s is invalid :(", qPrintable(_socket->peerAddress().toString()));
QByteArray is, should;
is = cert.toBase64();
should = _fingerprint.toBase64();
qDebug("Is %s and should be %s", is.data(), should.data());
}
_socket->disconnectFromHost();
}
void PVSDiscoveredServer::validateCertificate()
{
if (_validated) return; // Nothing to do, this one is legit
QDateTime now = QDateTime::currentDateTime();
if (_lastCheck.secsTo(now) < 30) return; // Too soon!
if (_host.isNull() || _port < 1 || _port > 65535) return; // Invalid
if (_socket != NULL) {
disconnect(_socket, SIGNAL(connected()), this, SLOT(sock_connected()));
disconnect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival()));
disconnect(_socket, SIGNAL(sslErrors(const QList<QSslError> &)),
this, SLOT(ssl_Error(const QList<QSslError> &))
);
_socket->abort();
_socket->deleteLater();
}
_socket = new QSslSocket(this);
_socket->setProtocol(QSsl::SslV3);
_socket->setPeerVerifyMode(QSslSocket::VerifyPeer);
connect(_socket, SIGNAL(encrypted()), this, SLOT(sock_connected()));
connect(_socket, SIGNAL(readyRead()), this, SLOT(sock_dataArrival()));
connect(_socket, SIGNAL(sslErrors(const QList<QSslError> &)),
this, SLOT(ssl_Error(const QList<QSslError> &))
);
_socket->connectToHostEncrypted(_host.toString(), _port);
_lastCheck = now;
}
bool PVSDiscoveredServer::hasFingerprint(QByteArray &fingerprint)
{
return _fingerprint == fingerprint;
}
bool PVSDiscoveredServer::hasHost(QHostAddress &host)
{
return _host == host;
}
void PVSDiscoveredServer::update(int port)
{
_port = port;
_lastUpdate = QDateTime::currentDateTime();
}
int PVSDiscoveredServer::getAge()
{
return _lastUpdate.secsTo(QDateTime::currentDateTime());
}
QString PVSDiscoveredServer::getName()
{
return _name;
}