| Home | ![]() |
This example demonstrates how to use QtSSLSocket to create a simple secure SSL server.
sslserver.h:
#ifndef SSLSERVER_H
#define SSLSERVER_H
#include <qserversocket.h>
class QtSSLSocket;
class SSLServerConnection : public QObject
{
Q_OBJECT
public:
SSLServerConnection(unsigned short int socket, QObject *parent = 0, const char *name = 0);
~SSLServerConnection();
public slots:
void acceptedClient();
void readData();
void connectionClosed();
void error(int);
private:
unsigned int readBytes;
unsigned int writtenBytes;
QtSSLSocket *sslsocket;
};
class SSLServer : public QServerSocket
{
Q_OBJECT
public:
SSLServer(short unsigned int port, QObject *parent = 0, const char *name = 0);
void newConnection(int socket);
};
#endif
sslserver.cpp:
#include "sslserver.h"
#include <qdir.h>
#include <qfileinfo.h>
#include <qptrlist.h>
#include <qdatetime.h>
#include <qtsslsocket.h>
#include <qserversocket.h>
SSLServer::SSLServer(short unsigned int port, QObject *parent, const char *name)
: QServerSocket(port, /* backlog = */ 1, parent, name)
{
}
void SSLServer::newConnection(int socket)
{
// As soon as a client connects, pass its incoming socket id to a
// SSLServerConnection child. This child is deleted after the
// connection is closed (see the connectionClosed() slot).
new SSLServerConnection(socket, this);
}
SSLServerConnection::SSLServerConnection(unsigned short int socket,
QObject *parent, const char *name)
: QObject(parent, name)
{
// Create an SSL socket and make its QSocket use our accepted
// socket, then give it the path to our certificate & private key
// file. For notes on this file, please check the provided
// "server.txt".
sslsocket = new QtSSLSocket(QtSSLSocket::Server, 0, this);
sslsocket->socket()->setSocket(socket);
sslsocket->setPathToCertificate("sslserver.pem");
sslsocket->setPathToPrivateKey("sslserver.pem");
// Notice the platform dependency here; the location of the CA
// certificate bundle is specific to the OS.
sslsocket->setPathToCACertDir("/etc/ssl/certs");
// Connect the SSL socket's signals to our slots.
connect(sslsocket, SIGNAL(accepted()), SLOT(acceptedClient()));
connect(sslsocket, SIGNAL(connectionClosed()), SLOT(connectionClosed()));
connect(sslsocket, SIGNAL(delayedCloseFinished()), SLOT(connectionClosed()));
connect(sslsocket, SIGNAL(readyRead()), SLOT(readData()));
connect(sslsocket, SIGNAL(error(int)), SLOT(error(int)));
// Call sslAccepted(). After this, when the SSL socket emits
// accepted(), we are ready to go. We ignore the return value of
// this function, because it will always fail the first time we
// call it.
sslsocket->sslAccept();
}
SSLServerConnection::~SSLServerConnection()
{
// Report that the connection has closed.
qDebug("Connection closed.");
}
void SSLServerConnection::acceptedClient()
{
// Provide feedback to the user about incoming connections. This
// slot is only called if the connection was established, so all
// communication is now encrypted.
qDebug("Accepted new client from %s",
sslsocket->socket()->peerAddress().toString().latin1());
// Print a simple DOS-like prompt. Write this to the SSL socket.
// The SSL socket encrypts the data, and sends it to the client.
QCString s = "Welcome to Fake-DOS 2.11\r\nC:\\>";
sslsocket->writeBlock(s, s.length());
}
void SSLServerConnection::readData()
{
// First, read all incoming data from the client. The SSL socket
// has already decrypted it for us. We assume that the client uses
// a plain text protocol, so we convert the data to a QString.
QString incoming(sslsocket->readAll());
// This server accepts only the commands "EXIT" and "DIR",
// although case insensitive. All other commands are rejected with
// "bad command or file name". Write response back to the client
// through the SSL socket.
QString command = incoming.upper().stripWhiteSpace();
if (command == "EXIT") {
QCString s = "system halted\r\n";
sslsocket->writeBlock(s, s.length());
sslsocket->close();
} else if (command == "DIR") {
QDir cwd(".");
const QFileInfoList *cwdlist = cwd.entryInfoList();
if (!cwdlist) {
QCString s = "unable to list directory contents\r\nC:\\>";
sslsocket->writeBlock(s, s.length());
} else {
QCString s = " Volume in drive C has no label.\r\n";
s += " Volume Serial Number is C564-1226\r\n\r\n";
s += " Directory of C:\\\r\n\r\n";
QPtrListIterator<QFileInfo> it(*cwdlist);
int nfiles = 0;
int ndirs = 0;
int tildes = 0;
while (it.current()) {
QFileInfo *f = *it;
QDate d = f->created().date();
QTime t = f->created().time();
QString line;
bool dots = f->fileName() == "." || f->fileName() == "..";
QString fname = dots ? QString("") : f->baseName().upper();
QString lname = dots ? f->fileName() : f->extension().upper().left(3);
if (fname.length() > 8) {
QString tmp;
tmp.sprintf("~%i", ++tildes);
fname = fname.left(8 - tmp.length()) + tmp;
}
if (f->isDir()) {
line.sprintf("%8s %3s <DIR> %02i-%02i-%02i %2i:%02i%c\r\n",
fname.latin1(), lname.latin1(), d.day(), d.month(),
(d.year() - 1900) % 100,
t.hour() % 12, t.minute(), t.hour() > 12 ? 'p' : 'a');
} else {
line.sprintf("%8s %3s %7u %02i-%02i-%02i %2i:%02i%c\r\n",
fname.latin1(), lname.latin1(), f->size(), d.day(), d.month(),
(d.year() - 1900) % 100, t.hour() % 12, t.minute(),
t.hour() > 12 ? 'p' : 'a');
}
s += line.local8Bit();
if ((*it)->isDir())
++ndirs;
else
++nfiles;
++it;
}
QString line;
line.sprintf("%16i File(s)\r\n", nfiles);
s += line.local8Bit();
line.sprintf("%16i Dir(s)\r\n", ndirs);
s += line.local8Bit();
s += "C:\\>";
sslsocket->writeBlock(s, s.length());
}
} else {
QCString s = "bad command or file name\r\nC:\\>";
sslsocket->writeBlock(s, s.length());
}
}
void SSLServerConnection::connectionClosed()
{
// Although the socket may be closing, we must not delete it until
// the delayed close is done.
if (sslsocket->socket()->state() == QSocket::Closing) {
connect(sslsocket->socket(), SIGNAL(delayedCloseFinished()), SLOT(deleteLater()));
} else {
deleteLater();
return;
}
qDebug("Connection closed.");
}
void SSLServerConnection::error(int)
{
// The SSL socket conveniently provides human readable error
// messages through the errorString() call. Note that sometimes
// the errors come directly from the underlying SSL library, and
// the quality of the text may vary.
qDebug("Error: %s", (const char *)sslsocket->errorString().local8Bit());
}
main.cpp:
#include <qapplication.h>
#include <stdlib.h>
#include <qfileinfo.h>
#include "sslserver.h"
/*
An SSL server that is started from the console.
This example demonstrates the use of the QtSSLSocket class in a
server application.
*/
int main(int argc, char *argv[])
{
QFileInfo cert("sslserver.pem");
if (!cert.exists()) {
qDebug("Note: This server requires the file sslserver.pem to exist, "
"and to contain the SSL private key and certificate for "
"this server, encoded in PEM format. Please read "
"server.txt for more information.");
return 1;
}
if (argc < 2) {
qDebug("usage: %s <port>", argv[0]);
qDebug("A simple SSL server.");
return 1;
}
QApplication app(argc, argv, false);
int port = atoi(argv[1]);
SSLServer sserver(port);
qDebug("Listening on port %i. Please press Ctrl-C to exit.", port);
return app.exec();
}
server.pro:
TEMPLATE = app INCLUDEPATH += . CONFIG += console include(../../src/qtsslsocket.pri) HEADERS += sslserver.h SOURCES += main.cpp sslserver.cpp
| Copyright © 2003-2006 Trolltech | Trademarks | Qt Solutions
|