summaryrefslogblamecommitdiffstats
path: root/src/server/net/sslserver.cpp
blob: c11f0aed1a4b7ded62f8fc0224c0117d4eb9f4b4 (plain) (tree)



















                                                                                
                   
 
                                            

                                



                       
                        

 



                               
                                                            
 
                                 

                             



                                                                       
                                               

                       
                                                           
                                                                                                                            

                                                                                                                                 


                                                                
                                                         
                                                                  
                                                                                               




                                                                                                                                                    


                                                                                          
                
                                                                              



                                            
                                                               
 

















                                                                                              

 
                                                     

                                                 
                                    







                                                       
                                             
 
                                                                                                   








                                                                                               

                                                                                                






                                                                                                      

                                                                                                






                                                                                                      
                       

 
/*
 # 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/SslServer.cpp
 #    - provide QTcpServer-like behaviour for SSL
 # -----------------------------------------------------------------------------
 */

#include "sslserver.h"
#include <QtNetwork/QSslCipher>
#include <QtNetwork/QSslSocket>
#include "certmanager.h"
#include <unistd.h>

SslServer::SslServer() : QTcpServer(nullptr)
{
	_tmr = startTimer(5123);
}

SslServer::~SslServer()
{
	killTimer(_tmr);
}

/**
 * Handle incomming connection.
 * @param socketDescriptor
 */
void SslServer::incomingConnection(qintptr socketDescriptor)
{
	static int certFails = 0;
	QSslKey key;
	QSslCertificate cert;
	if (!CertManager::getPrivateKeyAndCert("manager", key, cert)) {
		if (++certFails > 5) {
			CertManager::fatal();
		}
		::close((int)socketDescriptor);
		return;
	}
	QSslSocket *serverSocket = new QSslSocket(nullptr);
	connect(serverSocket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
	connect(serverSocket, SIGNAL(disconnected()), this, SLOT(sock_closed()));
	connect(serverSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sock_error(QAbstractSocket::SocketError)));
	serverSocket->setPrivateKey(key);
	serverSocket->setLocalCertificate(cert);
	serverSocket->setPeerVerifyMode(QSslSocket::VerifyNone);
	serverSocket->setProtocol(QSsl::SecureProtocols);
	if (serverSocket->setSocketDescriptor(socketDescriptor)) {
		// Once the connection is successfully encrypted, raise our newConnection event
		connect(serverSocket, &QSslSocket::encrypted, [=]() {
			disconnect(serverSocket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
			disconnect(serverSocket, SIGNAL(disconnected()), this, SLOT(sock_closed()));
			disconnect(serverSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(sock_error(QAbstractSocket::SocketError)));
		});
		connect(serverSocket, SIGNAL(encrypted()), this, SIGNAL(newConnection()));
		serverSocket->startServerEncryption();
		_pending.push_back(serverSocket);
	} else {
		qDebug() << "Failed to setSocketDescriptor on new SSL Socket";
		serverSocket->deleteLater();
	}
}

void SslServer::sslErrors(const QList<QSslError>& /* errors */)
{
	/*
	qDebug() << "Client caused sslErrors before connection:";
	for (QList<QSslError>::const_iterator it = errors.begin(); it != errors.end(); it++) {
		qDebug() << it->errorString();
	}
	*/
}

void SslServer::sock_closed()
{
	qDebug() << "Client closed connection before SSL handshake completed.";
	sender()->deleteLater();
}

void SslServer::sock_error(QAbstractSocket::SocketError err)
{
	qDebug() << "Client error before SSL handshake completed: " << err;
	sender()->deleteLater();
}

void SslServer::timerEvent(QTimerEvent* /* event */ )
{
	// Remove all sockets marked for deletion
	while (!_delete.isEmpty()) {
		QSslSocket *sock = _delete.takeFirst();
		sock->blockSignals(true);
		sock->deleteLater();
	}
	_delete = _pending;
	_pending.clear();
}

bool SslServer::hasPendingConnections() const
{
	for (QList<QSslSocket*>::const_iterator it(_pending.begin()); it != _pending.end(); it++) {
		qDebug("State: %d - Encrypted: %d", (int)(*it)->state(), (*it)->isEncrypted());
		if ((*it)->state() == QAbstractSocket::ConnectedState && (*it)->isEncrypted())
			return true;
	}
	return false;
}

QTcpSocket* SslServer::nextPendingConnection()
{
	for (QList<QSslSocket*>::iterator it(_pending.begin()); it != _pending.end(); it++) {
		if ((*it)->state() == QAbstractSocket::ConnectedState && (*it)->isEncrypted()) {
			QSslSocket *sock = *it;
			QObject::disconnect(sock, SIGNAL(encrypted()), this, SIGNAL(newConnection()));
			_pending.removeAll(sock);
			_delete.removeAll(sock);
			return sock;
		}
	}
	for (QList<QSslSocket*>::iterator it(_delete.begin()); it != _delete.end(); it++) {
		if ((*it)->state() == QAbstractSocket::ConnectedState && (*it)->isEncrypted()) {
			QSslSocket *sock = *it;
			QObject::disconnect(sock, SIGNAL(encrypted()), this, SIGNAL(newConnection()));
			_pending.removeAll(sock);
			_delete.removeAll(sock);
			return sock;
		}
	}
	return nullptr;
}