June 9th 2014, SSL Server /w QTcpServer
← June 8th 2014 QSslSocket | ● | June 9th 2014 SSL Client with QSslSocket →
The key component of the QTcpServer class is the incomingConnection() method. The default implementation creates a new QTcpSocket, attaches the socket to the actual incoming connection and puts it into a queue, where it is waiting to be handled by the nextConnection() call.
The default implementation obviously cannot be reused for secure connections, since it is hardwired to standard unencrypted sockets.
In order to use SSL encryption we overwrite the standard implementation of incomingConnection(), so that the standard socket queue is just not used. Instead we create and attach a new SSL socket for each incoming connection like so:
{
Q_OBJECT
public:
SSLServer(QObject *parent = NULL) : QTcpServer(parent) {}
virtual ~SSLServer() {}
// start listening
void start(QString certPath, QString keyPath, quint16 port = 0);
{
certPath_ = certPath;
keyPath_ = keyPath;
listen(QHostAddress::Any, port);
}
protected:
// handle new incoming connection
virtual void incomingConnection(int socketDescriptor)
{
// create new ssl server connection for each incoming connection
SSLServerConnection *connection =
new SSLServerConnection(socketDescriptor, certPath_, keyPath_, this);
// initiate handshake
connection->handshake();
}
QString certPath_;
QString keyPath_;
};
class SSLServerConnection: public QObject
{
Q_OBJECT
public:
SSLServerConnection(int socketDescriptor,
QString certPath, QString keyPath,
QObject *parent = NULL)
: QObject(parent)
{
// create new ssl socket for each incoming connection
socket_ = new QSslSocket(this);
socket_->setSocketDescriptor(socketDescriptor);
// configure ssl socket
socket_->setProtocol(QSsl::TlsV1);
socket_->setLocalCertificate(certPath);
socket_->setPrivateKey(keyPath);
// start reading from an established connection
connect(socket_, SIGNAL(readyRead()),
this, SLOT(startReading()));
// self-termination after socket has disconnected
connect(socket_, SIGNAL(disconnected()),
this, SLOT(deleteLater()));
}
virtual ~SSLServerConnection()
{
delete socket_;
}
// start ssl handshake
void handshake()
{
socket_->startServerEncryption();
}
protected:
QSslSocket *socket_;
protected slots:
// start reading after connection is established
void startReading()
{
// read data from the ssl socket
QByteArray data = socket_->readAll();
// test output
std::cout << QString(data).toStdString() << std::endl;
}
};
The server requires an event loop to be running. Each new SSL connection automatically destroys itself after being disconnected. This is achieved by connecting the disconnect() signal of the socket to the deleteLater() signal of the connection.
Thinking about a threaded server, the answer is simply that threads won’t speed things up, as long as the server is just busy waiting for connections and copying data chunks around. It might be worthwhile, if the server had a higher work load, but even compression is not adding to the work load, since the server does not have to compress data, only the client. For a threaded version of the client read below.
← June 8th 2014 QSslSocket | ● | June 9th 2014 SSL Client with QSslSocket →