I am still not clear with certain things.
Maybe this will help me clear doubts. The following is the code of a threaded SSL server.
main.cpp
#include <QApplication>
#include <QtCore>
#include <stdlib.h>
#include "server.h"
// Number of requests served
quint64 Served = 0;
int main(int argc, char *argv[]){
NServer server;
NServer serverTLS;
// Normal Server
return 2;
}
// SSL Server
return 2;
}
// Set this is a SSL server
serverTLS.isTLS = 1;
// Load the certificate
QFile cert
("./conf/cert.pem");
qDebug() << "Could not open cert.pem";
}
serverTLS.Certificate = QSslCertificate(&cert);
// Load the KEY
QFile key
("./conf/key.pem");
qDebug() << "Could not open key.pem";
}
serverTLS.SslKey = QSslKey(&key, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, "123456");
// Start the event loop
return capp.exec();
}
#include <QApplication>
#include <QtCore>
#include <stdlib.h>
#include "server.h"
// Number of requests served
quint64 Served = 0;
int main(int argc, char *argv[]){
QCoreApplication capp(argc, argv);
NServer server;
NServer serverTLS;
// Normal Server
if (!server.listen(QHostAddress::Any, 1780)) {
return 2;
}
// SSL Server
if (!serverTLS.listen(QHostAddress::Any, 1781)) {
return 2;
}
// Set this is a SSL server
serverTLS.isTLS = 1;
// Load the certificate
QFile cert("./conf/cert.pem");
if(!cert.open(QIODevice::ReadOnly)){
qDebug() << "Could not open cert.pem";
}
serverTLS.Certificate = QSslCertificate(&cert);
// Load the KEY
QFile key("./conf/key.pem");
if(!key.open(QIODevice::ReadOnly)){
qDebug() << "Could not open key.pem";
}
serverTLS.SslKey = QSslKey(&key, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, "123456");
// Start the event loop
return capp.exec();
}
To copy to clipboard, switch view to plain text mode
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QtNetwork>
#include <qdebug.h>
#include "thread.h"
// The Server Class
{
Q_OBJECT
public:
// Constructor
// Is this a SSL server ?
int isTLS;
// Certificate
QSslCertificate Certificate;
// Key
QSslKey SslKey;
protected:
void incomingConnection(int socketDescriptor);
};
#endif
#ifndef SERVER_H
#define SERVER_H
#include <QtNetwork>
#include <qdebug.h>
#include "thread.h"
// The Server Class
class NServer : public QTcpServer
{
Q_OBJECT
public:
// Constructor
NServer(QObject *parent = 0);
// Is this a SSL server ?
int isTLS;
// Certificate
QSslCertificate Certificate;
// Key
QSslKey SslKey;
protected:
void incomingConnection(int socketDescriptor);
};
#endif
To copy to clipboard, switch view to plain text mode
server.cpp
#include "server.h"
// Constructor
// Nothing to do in the constructor
}
// All incoming connections are sent to this function
void NServer::incomingConnection(int socketDescriptor){
Thread * thread = new Thread(socketDescriptor, this);
//pool.setMaxThreadCount(10000);
// Set the SSL Cert and Key if TLS is on
if(isTLS){
thread->isTLS = isTLS;
thread->Certificate = Certificate;
thread->SslKey = SslKey;
}
connect(thread->socket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(sslErrors(QList<QSslError>)));
connect(thread, SIGNAL(finished()), thread, SLOT(quit()));
//connect(thread, SIGNAL(finished()), thread, SLOT(test()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
// Start the thread
thread->start();
}
#include "server.h"
// Constructor
NServer::NServer(QObject *parent) : QTcpServer(parent), isTLS(0) {
// Nothing to do in the constructor
}
// All incoming connections are sent to this function
void NServer::incomingConnection(int socketDescriptor){
Thread * thread = new Thread(socketDescriptor, this);
//pool.setMaxThreadCount(10000);
// Set the SSL Cert and Key if TLS is on
if(isTLS){
thread->isTLS = isTLS;
thread->Certificate = Certificate;
thread->SslKey = SslKey;
}
connect(thread->socket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(sslErrors(QList<QSslError>)));
connect(thread, SIGNAL(finished()), thread, SLOT(quit()));
//connect(thread, SIGNAL(finished()), thread, SLOT(test()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
// Start the thread
thread->start();
}
To copy to clipboard, switch view to plain text mode
thread.h
#ifndef THREAD_H
#define THREAD_H
#include <QThread>
#include <QtNetwork>
#include <qdebug.h>
// Thread class
{
Q_OBJECT
public:
// Constructor
Thread
(int socketDescriptor,
QObject *parent
);
// This is the function which is called on a new connection
void run();
// Is it in TLS MODE ?
int isTLS;
// Certificate
QSslCertificate Certificate;
// Key
QSslKey SslKey;
// A socket pointer to the SOCKET so that we can use it to do stuff
QSslSocket * socket;
signals:
private:
// The Socket Descriptor
int socketDescriptor;
// If the output has started then no header should be allowed
bool outputStarted;
// SSL Socket Connection start
bool SSLSocket();
// TCP Socket Connection start
bool NormalSocket();
// Write Data to the socket
// Write a header
// Write the BODY
// Write the given BODY and Close the SOCKET as well.
// Closes the socket
void cleanup();
public slots:
// Closes the socket
void sslErrors(const QList<QSslError> &errors);
// SSL Socket Connection start
void handshakeComplete();
void test();
};
#endif
#ifndef THREAD_H
#define THREAD_H
#include <QThread>
#include <QtNetwork>
#include <qdebug.h>
// Thread class
class Thread : public QThread
{
Q_OBJECT
public:
// Constructor
Thread(int socketDescriptor, QObject *parent);
// This is the function which is called on a new connection
void run();
// Is it in TLS MODE ?
int isTLS;
// Certificate
QSslCertificate Certificate;
// Key
QSslKey SslKey;
// A socket pointer to the SOCKET so that we can use it to do stuff
QSslSocket * socket;
signals:
void error(QTcpSocket::SocketError socketError);
private:
// The Socket Descriptor
int socketDescriptor;
// If the output has started then no header should be allowed
bool outputStarted;
// SSL Socket Connection start
bool SSLSocket();
// TCP Socket Connection start
bool NormalSocket();
// Write Data to the socket
bool socketWrite(const QByteArray &text);
// Write a header
bool header(const QByteArray &text);
// Write the BODY
bool write(const QByteArray &text);
// Write the given BODY and Close the SOCKET as well.
bool end(const QByteArray &text);
// Closes the socket
void cleanup();
public slots:
// Closes the socket
void sslErrors(const QList<QSslError> &errors);
// SSL Socket Connection start
void handshakeComplete();
void test();
};
#endif
To copy to clipboard, switch view to plain text mode
thread.cpp
#include "thread.h"
extern quint64 Served;
// Constructor
Thread
::Thread(int socketDescriptor,
QObject *parent
) : QThread(parent
), socketDescriptor
(socketDescriptor
) {
this->isTLS = 0;
this->setTerminationEnabled(true);
qDebug() << "Socket" << socketDescriptor;
//qDebug()<< QThread::idealThreadCount();
}
void Thread::test(){
qDebug() << "Finished";
}
// When its a normal connection
bool Thread::NormalSocket(){
// Create the Socket
socket = new QSslSocket;
if (!socket->setSocketDescriptor(socketDescriptor)) {
emit error(socket->error());
delete socket;
return false;
}
//qDebug() << "In Normal Socket";
return true;
}
// SSL Connection hence SSL Socket
bool Thread::SSLSocket(){
// Create the Socket
socket = new QSslSocket;
//qDebug() << Certificate;
//qDebug() << SslKey;
connect(socket, SIGNAL(encrypted()),
this, SLOT(handshakeComplete()));
connect(socket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(sslErrors(QList<QSslError>)));
// Set the protocol and certificates
socket->setProtocol(QSsl::AnyProtocol);
socket->setLocalCertificate(Certificate);
socket->setPrivateKey(SslKey);
// Set the descriptor
if (!socket->setSocketDescriptor(socketDescriptor)) {
emit error(socket->error());
delete socket;
return false;
}
// No need to verify the peer
socket->setPeerVerifyMode(QSslSocket::VerifyNone);
// Start the encryption
socket->startServerEncryption();
// Wait for the excryption to start
socket->waitForEncrypted(1000);
return true;
}
// Called when the thread is started
void Thread::run(){
//this->exec();
Served++;
qDebug() << "Num Req : " << Served;
// SSL Socket Start
if(isTLS > 0){
qDebug() << "SSL";
if(!SSLSocket()){
return;
}
// Normal Socket
}else{
if(!NormalSocket()){
return;
}
}
// Wait for it to become read ready for a MAX of 1 second
socket->waitForReadyRead(1000);
//qDebug()<<"Wait";
QMap<QByteArray, QByteArray> headers;
//qDebug() << "Enc : " << socket->isEncrypted();
//qDebug() << "Errors : " << socket->sslErrors();
/////////////////////////////////////
// Determine its an DATA / HTTP Call
/////////////////////////////////////
// Get the Request Header
req = socket->read(81920);
//req = socket->readAll();
//qDebug() << "Req : " << req;
"Content-Type: text/html; charset=\"utf-8\"\r\n"
"\r\n"
"<form method=\"post\" action=\"\" name=\"input\">"
"<input type=\"text\" value=\"test\">"
"<input type=\"submit\" value=\"test\">"
"</form>\n"
"Test"
"\r\n"
"\r\n"
"\r\n";
this->write(block);
/*unsigned char * test = (unsigned char *)malloc(134217728);
this->sleep(10);
free(test);*/
//this->write(block);
cleanup();
//delete socket;
//emit finished();
}
socket->write(text);
return socket->flush();
}
void Thread::cleanup(){
socket->disconnectFromHost();
socket->waitForDisconnected();
}
//qDebug() << "Cleaned";
// Clear the socket
delete socket;
// Delete the thread
//this->exit(0);
//this->wait();
//this->deleteLater();
}
if(outputStarted){
return false;
}
return this->socketWrite(text);
}
// Set that output has been started
outputStarted = true;
return this->socketWrite(text);
}
// Set that output has been started
outputStarted = true;
return this->socketWrite(text);
}
// Called when there are SSL errors
void Thread::sslErrors(const QList<QSslError> &errors){
foreach (const QSslError &error, errors){
qDebug() << "[Backup::sslErrors] " << error.errorString();
}
// Ignore Errors
//socket->ignoreSslErrors();
}
// SSL handshake complete
void Thread::handshakeComplete(){
qDebug() << "[Thread::handshakeComplete]";
}
#include "thread.h"
extern quint64 Served;
// Constructor
Thread::Thread(int socketDescriptor, QObject *parent)
: QThread(parent), socketDescriptor(socketDescriptor)
{
this->isTLS = 0;
this->setTerminationEnabled(true);
qDebug() << "Socket" << socketDescriptor;
//qDebug()<< QThread::idealThreadCount();
}
void Thread::test(){
qDebug() << "Finished";
}
// When its a normal connection
bool Thread::NormalSocket(){
// Create the Socket
socket = new QSslSocket;
if (!socket->setSocketDescriptor(socketDescriptor)) {
emit error(socket->error());
delete socket;
return false;
}
//qDebug() << "In Normal Socket";
return true;
}
// SSL Connection hence SSL Socket
bool Thread::SSLSocket(){
// Create the Socket
socket = new QSslSocket;
//qDebug() << Certificate;
//qDebug() << SslKey;
connect(socket, SIGNAL(encrypted()),
this, SLOT(handshakeComplete()));
connect(socket, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(sslErrors(QList<QSslError>)));
// Set the protocol and certificates
socket->setProtocol(QSsl::AnyProtocol);
socket->setLocalCertificate(Certificate);
socket->setPrivateKey(SslKey);
// Set the descriptor
if (!socket->setSocketDescriptor(socketDescriptor)) {
emit error(socket->error());
delete socket;
return false;
}
// No need to verify the peer
socket->setPeerVerifyMode(QSslSocket::VerifyNone);
// Start the encryption
socket->startServerEncryption();
// Wait for the excryption to start
socket->waitForEncrypted(1000);
return true;
}
// Called when the thread is started
void Thread::run(){
//this->exec();
Served++;
qDebug() << "Num Req : " << Served;
// SSL Socket Start
if(isTLS > 0){
qDebug() << "SSL";
if(!SSLSocket()){
return;
}
// Normal Socket
}else{
if(!NormalSocket()){
return;
}
}
// Wait for it to become read ready for a MAX of 1 second
socket->waitForReadyRead(1000);
//qDebug()<<"Wait";
QByteArray req;
QMap<QByteArray, QByteArray> headers;
QByteArray reqType;
//qDebug() << "Enc : " << socket->isEncrypted();
//qDebug() << "Errors : " << socket->sslErrors();
/////////////////////////////////////
// Determine its an DATA / HTTP Call
/////////////////////////////////////
// Get the Request Header
req = socket->read(81920);
//req = socket->readAll();
//qDebug() << "Req : " << req;
QByteArray block = "HTTP/1.0 200 Ok\r\n"
"Content-Type: text/html; charset=\"utf-8\"\r\n"
"\r\n"
"<form method=\"post\" action=\"\" name=\"input\">"
"<input type=\"text\" value=\"test\">"
"<input type=\"submit\" value=\"test\">"
"</form>\n"
"Test"
"\r\n"
"\r\n"
"\r\n";
this->write(block);
/*unsigned char * test = (unsigned char *)malloc(134217728);
this->sleep(10);
free(test);*/
//this->write(block);
cleanup();
//delete socket;
//emit finished();
}
bool Thread::socketWrite(const QByteArray &text){
socket->write(text);
return socket->flush();
}
void Thread::cleanup(){
socket->disconnectFromHost();
if(socket->state() != QAbstractSocket::UnconnectedState){
socket->waitForDisconnected();
}
//qDebug() << "Cleaned";
// Clear the socket
delete socket;
// Delete the thread
//this->exit(0);
//this->wait();
//this->deleteLater();
}
bool Thread::header(const QByteArray &text){
if(outputStarted){
return false;
}
return this->socketWrite(text);
}
bool Thread::write(const QByteArray &text){
// Set that output has been started
outputStarted = true;
return this->socketWrite(text);
}
bool Thread::end(const QByteArray &text){
// Set that output has been started
outputStarted = true;
return this->socketWrite(text);
}
// Called when there are SSL errors
void Thread::sslErrors(const QList<QSslError> &errors){
foreach (const QSslError &error, errors){
qDebug() << "[Backup::sslErrors] " << error.errorString();
}
// Ignore Errors
//socket->ignoreSslErrors();
}
// SSL handshake complete
void Thread::handshakeComplete(){
qDebug() << "[Thread::handshakeComplete]";
}
To copy to clipboard, switch view to plain text mode
When I run this application I get an error as follows :
QObject::connect: Cannot queue arguments of type 'QList<QSslError>'
(Make sure 'QList<QSslError>' is registered using qRegisterMetaType().)
I am not able to understand why is this so ?
What is the corrective code for this ?
Bookmarks