Document DTLS examples

Task-number: QTBUG-68070
Change-Id: I2b08322049005b02f1ed680bee21992ade16813a
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Paul Wicking <paul.wicking@qt.io>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Timur Pocheptsov 2018-08-06 12:05:26 +02:00
parent 4c089601d7
commit 5b8d5c7493
13 changed files with 255 additions and 27 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -29,9 +29,96 @@
\example secureudpclient \example secureudpclient
\title DTLS client \title DTLS client
\ingroup examples-network \ingroup examples-network
\brief Demonstrates how to implement a simple DTLS client \brief This example demonstrates how to implement client-side DTLS connections.
This example uses QUdpSocket, QDtlsClientVerifier, and QDtls to securely \image secureudpclient-example.png Screenshot of the DTLS client example.
communicate over the User Datagram Protocol with DTLS servers.
\note The DTLS client example is intended to be run alongside the \l{secureudpserver}{DTLS server} example.
The example DTLS client can establish several DTLS connections to one
or many DTLS servers. A client-side DTLS connection is implemented by the
DtlsAssociation class. This class uses QUdpSocket to read and write datagrams
and QDtls for encryption:
\snippet secureudpclient/association.h 0
The constructor sets the minimal TLS configuration for the new DTLS connection,
and sets the address and the port of the server:
\dots
\snippet secureudpclient/association.cpp 1
\dots
The QDtls::handshakeTimeout() signal is connected to the handleTimeout() slot
to deal with packet loss and retransmission during the handshake phase:
\dots
\snippet secureudpclient/association.cpp 2
\dots
To ensure we receive only the datagrams from the server, we connect our UDP socket to the server:
\dots
\snippet secureudpclient/association.cpp 3
\dots
The QUdpSocket::readyRead() signal is connected to the readyRead() slot:
\dots
\snippet secureudpclient/association.cpp 13
\dots
When a secure connection to a server is established, a DtlsAssociation object
will be sending short ping messages to the server, using a timer:
\snippet secureudpclient/association.cpp 4
startHandshake() starts a handshake with the server:
\snippet secureudpclient/association.cpp 5
The readyRead() slot reads a datagram sent by the server:
\snippet secureudpclient/association.cpp 6
If the handshake was already completed, this datagram is decrypted:
\snippet secureudpclient/association.cpp 7
otherwise, we try to continue the handshake:
\snippet secureudpclient/association.cpp 8
When the handshake has completed, we send our first ping message:
\snippet secureudpclient/association.cpp 9
The pskRequired() slot provides the Pre-Shared Key (PSK) needed during the handshake
phase:
\snippet secureudpclient/association.cpp 14
\note For the sake of brevity, the definition of pskRequired() is oversimplified.
The documentation for the QSslPreSharedKeyAuthenticator class explains in detail
how this slot can be properly implemented.
pingTimeout() sends an encrypted message to the server:
\snippet secureudpclient/association.cpp 10
During the handshake phase the client must handle possible timeouts, which
can happen due to packet loss. The handshakeTimeout() slot retransmits
the handshake messages:
\snippet secureudpclient/association.cpp 11
Before a client connection is destroyed, its DTLS connection must be shut down:
\snippet secureudpclient/association.cpp 12
Error messages, informational messages, and decrypted responses from servers
are displayed by the UI:
\snippet secureudpclient/mainwindow.cpp 0
*/ */

View File

@ -29,8 +29,103 @@
\example secureudpserver \example secureudpserver
\title DTLS server \title DTLS server
\ingroup examples-network \ingroup examples-network
\brief Demonstrates how to implement a simple DTLS server \brief This examples demonstrates how to implement a simple DTLS server.
This example uses QUdpSocket, QDtlsClientVerifier, and QDtls to securely respond \image secureudpserver-example.png Screenshot of the DTLS server example.
to DTLS client requests over the User Datagram Protocol.
\note The DTLS server example is intended to be run alongside the \l{secureudpclient}{DTLS client} example.
The server is implemented by the DtlsServer class. It uses QUdpSocket,
QDtlsClientVerifier, and QDtls to test each client's reachability, complete a handshake,
and read and write encrypted messages.
\snippet secureudpserver/server.h 0
The constructor connects the QUdpSocket::readyRead() signal to its
readyRead() slot and sets the minimal needed TLS configuration:
\snippet secureudpserver/server.cpp 1
\note The server is not using a certificate and is relying on Pre-Shared
Key (PSK) handshake.
listen() binds QUdpSocket:
\snippet secureudpserver/server.cpp 2
The readyRead() slot processes incoming datagrams:
\dots
\snippet secureudpserver/server.cpp 3
\dots
After extracting an address and a port number, the server first tests
if it's a datagram from an already known peer:
\dots
\snippet secureudpserver/server.cpp 4
\dots
If it is a new, unknown address and port, the datagram is processed as a
potential ClientHello message, sent by a DTLS client:
\dots
\snippet secureudpserver/server.cpp 5
\dots
If it's a known DTLS client, the server either decrypts the datagram:
\dots
\snippet secureudpserver/server.cpp 6
\dots
or continues a handshake with this peer:
\dots
\snippet secureudpserver/server.cpp 7
\dots
handleNewConnection() verifies it's a reachable DTLS client, or sends a
HelloVerifyRequest:
\snippet secureudpserver/server.cpp 8
\dots
If the new client was verified to be a reachable DTLS client, the server creates
and configures a new QDtls object, and starts a server-side handshake:
\dots
\snippet secureudpserver/server.cpp 9
\dots
doHandshake() progresses through the handshake phase:
\snippet secureudpserver/server.cpp 11
During the handshake phase, the QDtls::pskRequired() signal is emitted and
the pskRequired() slot provides the preshared key:
\snippet secureudpserver/server.cpp 13
\note For the sake of brevity, the definition of pskRequired() is oversimplified.
The documentation for the QSslPreSharedKeyAuthenticator class explains in detail
how this slot can be properly implemented.
After the handshake is completed for the network peer, an encrypted DTLS
connection is considered to be established and the server decrypts subsequent
datagrams, sent by the peer, by calling decryptDatagram(). The server also
sends an encrypted response to the peer:
\snippet secureudpserver/server.cpp 12
The server closes its DTLS connections by calling QDtls::shutdown():
\snippet secureudpserver/server.cpp 14
During its operation, the server reports errors, informational messages, and
decrypted datagrams, by emitting signals errorMessage(), warningMessage(),
infoMessage(), and datagramReceived(). These messages are logged by the server's
UI:
\snippet secureudpserver/mainwindow.cpp 0
*/ */

View File

@ -69,7 +69,6 @@ class AddressDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit AddressDialog(QWidget *parent = nullptr); explicit AddressDialog(QWidget *parent = nullptr);
~AddressDialog(); ~AddressDialog();
@ -77,7 +76,6 @@ public:
quint16 remotePort() const; quint16 remotePort() const;
private: private:
void setupHostSelector(); void setupHostSelector();
void setupPortSelector(); void setupPortSelector();

View File

@ -57,27 +57,38 @@ DtlsAssociation::DtlsAssociation(const QHostAddress &address, quint16 port,
: name(connectionName), : name(connectionName),
crypto(QSslSocket::SslClientMode) crypto(QSslSocket::SslClientMode)
{ {
//! [1]
auto configuration = QSslConfiguration::defaultDtlsConfiguration(); auto configuration = QSslConfiguration::defaultDtlsConfiguration();
configuration.setPeerVerifyMode(QSslSocket::VerifyNone); configuration.setPeerVerifyMode(QSslSocket::VerifyNone);
crypto.setPeer(address, port); crypto.setPeer(address, port);
crypto.setDtlsConfiguration(configuration); crypto.setDtlsConfiguration(configuration);
//! [1]
//! [2]
connect(&crypto, &QDtls::handshakeTimeout, this, &DtlsAssociation::handshakeTimeout); connect(&crypto, &QDtls::handshakeTimeout, this, &DtlsAssociation::handshakeTimeout);
//! [2]
connect(&crypto, &QDtls::pskRequired, this, &DtlsAssociation::pskRequired); connect(&crypto, &QDtls::pskRequired, this, &DtlsAssociation::pskRequired);
//! [3]
socket.connectToHost(address.toString(), port); socket.connectToHost(address.toString(), port);
//! [3]
//! [13]
connect(&socket, &QUdpSocket::readyRead, this, &DtlsAssociation::readyRead); connect(&socket, &QUdpSocket::readyRead, this, &DtlsAssociation::readyRead);
//! [13]
//! [4]
pingTimer.setInterval(5000); pingTimer.setInterval(5000);
connect(&pingTimer, &QTimer::timeout, this, &DtlsAssociation::pingTimeout); connect(&pingTimer, &QTimer::timeout, this, &DtlsAssociation::pingTimeout);
//! [4]
} }
//! [12]
DtlsAssociation::~DtlsAssociation() DtlsAssociation::~DtlsAssociation()
{ {
if (crypto.isConnectionEncrypted()) if (crypto.isConnectionEncrypted())
crypto.shutdown(&socket); crypto.shutdown(&socket);
} }
//! [12]
//! [5]
void DtlsAssociation::startHandshake() void DtlsAssociation::startHandshake()
{ {
if (socket.state() != QAbstractSocket::ConnectedState) { if (socket.state() != QAbstractSocket::ConnectedState) {
@ -86,11 +97,12 @@ void DtlsAssociation::startHandshake()
return; return;
} }
if (!crypto.doHandshake(&socket, {})) if (!crypto.doHandshake(&socket))
emit errorMessage(tr("%1: failed to start a handshake - %2").arg(name, crypto.dtlsErrorString())); emit errorMessage(tr("%1: failed to start a handshake - %2").arg(name, crypto.dtlsErrorString()));
else else
emit infoMessage(tr("%1: starting a handshake").arg(name)); emit infoMessage(tr("%1: starting a handshake").arg(name));
} }
//! [5]
void DtlsAssociation::udpSocketConnected() void DtlsAssociation::udpSocketConnected()
{ {
@ -100,7 +112,8 @@ void DtlsAssociation::udpSocketConnected()
void DtlsAssociation::readyRead() void DtlsAssociation::readyRead()
{ {
QByteArray dgram(socket.pendingDatagramSize(), '\0'); //! [6]
QByteArray dgram(socket.pendingDatagramSize(), Qt::Uninitialized);
const qint64 bytesRead = socket.readDatagram(dgram.data(), dgram.size()); const qint64 bytesRead = socket.readDatagram(dgram.data(), dgram.size());
if (bytesRead <= 0) { if (bytesRead <= 0) {
emit warningMessage(tr("%1: spurious read notification?").arg(name)); emit warningMessage(tr("%1: spurious read notification?").arg(name));
@ -108,6 +121,8 @@ void DtlsAssociation::readyRead()
} }
dgram.resize(bytesRead); dgram.resize(bytesRead);
//! [6]
//! [7]
if (crypto.isConnectionEncrypted()) { if (crypto.isConnectionEncrypted()) {
const QByteArray plainText = crypto.decryptDatagram(&socket, dgram); const QByteArray plainText = crypto.decryptDatagram(&socket, dgram);
if (plainText.size()) { if (plainText.size()) {
@ -124,27 +139,36 @@ void DtlsAssociation::readyRead()
emit warningMessage(tr("%1: zero-length datagram received?").arg(name)); emit warningMessage(tr("%1: zero-length datagram received?").arg(name));
} else { } else {
//! [7]
//! [8]
if (!crypto.doHandshake(&socket, dgram)) { if (!crypto.doHandshake(&socket, dgram)) {
emit errorMessage(tr("%1: handshake error - %2").arg(name, crypto.dtlsErrorString())); emit errorMessage(tr("%1: handshake error - %2").arg(name, crypto.dtlsErrorString()));
return; return;
} }
//! [8]
//! [9]
if (crypto.isConnectionEncrypted()) { if (crypto.isConnectionEncrypted()) {
emit infoMessage(tr("%1: encrypted connection established!").arg(name)); emit infoMessage(tr("%1: encrypted connection established!").arg(name));
pingTimer.start(); pingTimer.start();
pingTimeout(); pingTimeout();
} else { } else {
//! [9]
emit infoMessage(tr("%1: continuing with handshake ...").arg(name)); emit infoMessage(tr("%1: continuing with handshake ...").arg(name));
} }
} }
} }
//! [11]
void DtlsAssociation::handshakeTimeout() void DtlsAssociation::handshakeTimeout()
{ {
emit warningMessage(tr("%1: handshake timeout, trying to re-transmit").arg(name)); emit warningMessage(tr("%1: handshake timeout, trying to re-transmit").arg(name));
if (!crypto.handleTimeout(&socket)) if (!crypto.handleTimeout(&socket))
emit errorMessage(tr("%1: failed to re-transmit - %2").arg(name, crypto.dtlsErrorString())); emit errorMessage(tr("%1: failed to re-transmit - %2").arg(name, crypto.dtlsErrorString()));
} }
//! [11]
//! [14]
void DtlsAssociation::pskRequired(QSslPreSharedKeyAuthenticator *auth) void DtlsAssociation::pskRequired(QSslPreSharedKeyAuthenticator *auth)
{ {
Q_ASSERT(auth); Q_ASSERT(auth);
@ -153,7 +177,9 @@ void DtlsAssociation::pskRequired(QSslPreSharedKeyAuthenticator *auth)
auth->setIdentity(name.toLatin1()); auth->setIdentity(name.toLatin1());
auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f")); auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f"));
} }
//! [14]
//! [10]
void DtlsAssociation::pingTimeout() void DtlsAssociation::pingTimeout()
{ {
static const QString message = QStringLiteral("I am %1, please, accept our ping %2"); static const QString message = QStringLiteral("I am %1, please, accept our ping %2");
@ -166,5 +192,6 @@ void DtlsAssociation::pingTimeout()
++ping; ++ping;
} }
//! [10]
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -55,19 +55,18 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
//! [0]
class DtlsAssociation : public QObject class DtlsAssociation : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
DtlsAssociation(const QHostAddress &address, quint16 port, DtlsAssociation(const QHostAddress &address, quint16 port,
const QString &connectionName); const QString &connectionName);
~DtlsAssociation(); ~DtlsAssociation();
void startHandshake(); void startHandshake();
signals: signals:
void errorMessage(const QString &message); void errorMessage(const QString &message);
void warningMessage(const QString &message); void warningMessage(const QString &message);
void infoMessage(const QString &message); void infoMessage(const QString &message);
@ -75,7 +74,6 @@ signals:
const QByteArray &plainText); const QByteArray &plainText);
private slots: private slots:
void udpSocketConnected(); void udpSocketConnected();
void readyRead(); void readyRead();
void handshakeTimeout(); void handshakeTimeout();
@ -83,7 +81,6 @@ private slots:
void pingTimeout(); void pingTimeout();
private: private:
QString name; QString name;
QUdpSocket socket; QUdpSocket socket;
QDtls crypto; QDtls crypto;
@ -93,6 +90,7 @@ private:
Q_DISABLE_COPY(DtlsAssociation) Q_DISABLE_COPY(DtlsAssociation)
}; };
//! [0]
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -72,6 +72,8 @@ MainWindow::~MainWindow()
delete ui; delete ui;
} }
//! [0]
const QString colorizer(QStringLiteral("<font color=\"%1\">%2</font><br>")); const QString colorizer(QStringLiteral("<font color=\"%1\">%2</font><br>"));
void MainWindow::addErrorMessage(const QString &message) void MainWindow::addErrorMessage(const QString &message)
@ -102,6 +104,8 @@ void MainWindow::addServerResponse(const QString &clientInfo, const QByteArray &
ui->serverMessages->insertHtml(colorizer.arg(messageColor, html)); ui->serverMessages->insertHtml(colorizer.arg(messageColor, html));
} }
//! [0]
void MainWindow::on_connectButton_clicked() void MainWindow::on_connectButton_clicked()
{ {
if (lookupId != -1) { if (lookupId != -1) {

View File

@ -76,7 +76,6 @@ class MainWindow : public QMainWindow
Q_OBJECT Q_OBJECT
public: public:
explicit MainWindow(QWidget *parent = nullptr); explicit MainWindow(QWidget *parent = nullptr);
~MainWindow(); ~MainWindow();
@ -94,7 +93,6 @@ private slots:
void lookupFinished(const QHostInfo &hostInfo); void lookupFinished(const QHostInfo &hostInfo);
private: private:
void updateUi(); void updateUi();
void startNewConnection(const QHostAddress &address); void startNewConnection(const QHostAddress &address);

View File

@ -104,6 +104,7 @@ void MainWindow::updateUi()
: ui->startButton->setText(tr("Start listening")); : ui->startButton->setText(tr("Start listening"));
} }
//! [0]
const QString colorizer(QStringLiteral("<font color=\"%1\">%2</font><br>")); const QString colorizer(QStringLiteral("<font color=\"%1\">%2</font><br>"));
void MainWindow::addErrorMessage(const QString &message) void MainWindow::addErrorMessage(const QString &message)
@ -134,3 +135,4 @@ void MainWindow::addClientMessage(const QString &peerInfo, const QByteArray &dat
QString::fromUtf8(plainText)); QString::fromUtf8(plainText));
ui->messages->insertHtml(colorizer.arg(messageColor, html)); ui->messages->insertHtml(colorizer.arg(messageColor, html));
} }
//! [0]

View File

@ -69,12 +69,10 @@ class MainWindow : public QMainWindow
Q_OBJECT Q_OBJECT
public: public:
MainWindow(); MainWindow();
~MainWindow(); ~MainWindow();
private slots: private slots:
void addErrorMessage(const QString &message); void addErrorMessage(const QString &message);
void addWarningMessage(const QString &message); void addWarningMessage(const QString &message);
void addInfoMessage(const QString &message); void addInfoMessage(const QString &message);
@ -85,7 +83,6 @@ private slots:
void on_quitButton_clicked(); void on_quitButton_clicked();
private: private:
void updateUi(); void updateUi();
Ui::MainWindow *ui = nullptr; Ui::MainWindow *ui = nullptr;

View File

@ -87,6 +87,7 @@ QString connection_info(QSharedPointer<QDtls> connection)
} // unnamed namespace } // unnamed namespace
//! [1]
DtlsServer::DtlsServer() DtlsServer::DtlsServer()
{ {
connect(&serverSocket, &QAbstractSocket::readyRead, this, &DtlsServer::readyRead); connect(&serverSocket, &QAbstractSocket::readyRead, this, &DtlsServer::readyRead);
@ -94,12 +95,14 @@ DtlsServer::DtlsServer()
serverConfiguration.setPreSharedKeyIdentityHint("Qt DTLS example server"); serverConfiguration.setPreSharedKeyIdentityHint("Qt DTLS example server");
serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone); serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
} }
//! [1]
DtlsServer::~DtlsServer() DtlsServer::~DtlsServer()
{ {
shutdown(); shutdown();
} }
//! [2]
bool DtlsServer::listen(const QHostAddress &address, quint16 port) bool DtlsServer::listen(const QHostAddress &address, quint16 port)
{ {
if (address != serverSocket.localAddress() || port != serverSocket.localPort()) { if (address != serverSocket.localAddress() || port != serverSocket.localPort()) {
@ -113,6 +116,7 @@ bool DtlsServer::listen(const QHostAddress &address, quint16 port)
return listening; return listening;
} }
//! [2]
bool DtlsServer::isListening() const bool DtlsServer::isListening() const
{ {
@ -126,6 +130,7 @@ void DtlsServer::close()
void DtlsServer::readyRead() void DtlsServer::readyRead()
{ {
//! [3]
const qint64 bytesToRead = serverSocket.pendingDatagramSize(); const qint64 bytesToRead = serverSocket.pendingDatagramSize();
if (bytesToRead <= 0) { if (bytesToRead <= 0) {
emit warningMessage(tr("A spurious read notification")); emit warningMessage(tr("A spurious read notification"));
@ -143,7 +148,8 @@ void DtlsServer::readyRead()
} }
dgram.resize(bytesRead); dgram.resize(bytesRead);
//! [3]
//! [4]
if (peerAddress.isNull() || !peerPort) { if (peerAddress.isNull() || !peerPort) {
emit warningMessage(tr("Failed to extract peer info (address, port)")); emit warningMessage(tr("Failed to extract peer info (address, port)"));
return; return;
@ -154,20 +160,28 @@ void DtlsServer::readyRead()
return connection->peerAddress() == peerAddress return connection->peerAddress() == peerAddress
&& connection->peerPort() == peerPort; && connection->peerPort() == peerPort;
}); });
//! [4]
//! [5]
if (client == knownClients.end()) if (client == knownClients.end())
return handleNewConnection(peerAddress, peerPort, dgram); return handleNewConnection(peerAddress, peerPort, dgram);
//! [5]
//! [6]
if ((*client)->isConnectionEncrypted()) { if ((*client)->isConnectionEncrypted()) {
decryptDatagram(*client, dgram); decryptDatagram(*client, dgram);
if ((*client)->dtlsError() == QDtlsError::RemoteClosedConnectionError) if ((*client)->dtlsError() == QDtlsError::RemoteClosedConnectionError)
knownClients.erase(client); knownClients.erase(client);
return; return;
} }
//! [6]
//! [7]
doHandshake(*client, dgram); doHandshake(*client, dgram);
//! [7]
} }
//! [13]
void DtlsServer::pskRequired(QSslPreSharedKeyAuthenticator *auth) void DtlsServer::pskRequired(QSslPreSharedKeyAuthenticator *auth)
{ {
Q_ASSERT(auth); Q_ASSERT(auth);
@ -176,7 +190,9 @@ void DtlsServer::pskRequired(QSslPreSharedKeyAuthenticator *auth)
.arg(QString::fromLatin1(auth->identity()))); .arg(QString::fromLatin1(auth->identity())));
auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f")); auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f"));
} }
//! [13]
//! [8]
void DtlsServer::handleNewConnection(const QHostAddress &peerAddress, void DtlsServer::handleNewConnection(const QHostAddress &peerAddress,
quint16 peerPort, const QByteArray &clientHello) quint16 peerPort, const QByteArray &clientHello)
{ {
@ -186,7 +202,8 @@ void DtlsServer::handleNewConnection(const QHostAddress &peerAddress,
const QString peerInfo = peer_info(peerAddress, peerPort); const QString peerInfo = peer_info(peerAddress, peerPort);
if (cookieSender.verifyClient(&serverSocket, clientHello, peerAddress, peerPort)) { if (cookieSender.verifyClient(&serverSocket, clientHello, peerAddress, peerPort)) {
emit infoMessage(peerInfo + tr(": verified, starting a handshake")); emit infoMessage(peerInfo + tr(": verified, starting a handshake"));
//! [8]
//! [9]
DtlsConnection newConnection(new QDtls(QSslSocket::SslServerMode)); DtlsConnection newConnection(new QDtls(QSslSocket::SslServerMode));
newConnection->setDtlsConfiguration(serverConfiguration); newConnection->setDtlsConfiguration(serverConfiguration);
newConnection->setPeer(peerAddress, peerPort); newConnection->setPeer(peerAddress, peerPort);
@ -194,6 +211,7 @@ void DtlsServer::handleNewConnection(const QHostAddress &peerAddress,
this, &DtlsServer::pskRequired); this, &DtlsServer::pskRequired);
knownClients.push_back(newConnection); knownClients.push_back(newConnection);
doHandshake(newConnection, clientHello); doHandshake(newConnection, clientHello);
//! [9]
} else if (cookieSender.dtlsError() != QDtlsError::NoError) { } else if (cookieSender.dtlsError() != QDtlsError::NoError) {
emit errorMessage(tr("DTLS error: ") + cookieSender.dtlsErrorString()); emit errorMessage(tr("DTLS error: ") + cookieSender.dtlsErrorString());
} else { } else {
@ -201,6 +219,7 @@ void DtlsServer::handleNewConnection(const QHostAddress &peerAddress,
} }
} }
//! [11]
void DtlsServer::doHandshake(DtlsConnection newConnection, const QByteArray &clientHello) void DtlsServer::doHandshake(DtlsConnection newConnection, const QByteArray &clientHello)
{ {
const bool result = newConnection->doHandshake(&serverSocket, clientHello); const bool result = newConnection->doHandshake(&serverSocket, clientHello);
@ -223,7 +242,9 @@ void DtlsServer::doHandshake(DtlsConnection newConnection, const QByteArray &cli
Q_UNREACHABLE(); Q_UNREACHABLE();
} }
} }
//! [11]
//! [12]
void DtlsServer::decryptDatagram(DtlsConnection connection, const QByteArray &clientMessage) void DtlsServer::decryptDatagram(DtlsConnection connection, const QByteArray &clientMessage)
{ {
Q_ASSERT(connection->isConnectionEncrypted()); Q_ASSERT(connection->isConnectionEncrypted());
@ -239,7 +260,9 @@ void DtlsServer::decryptDatagram(DtlsConnection connection, const QByteArray &cl
emit errorMessage(peerInfo + ": " + connection->dtlsErrorString()); emit errorMessage(peerInfo + ": " + connection->dtlsErrorString());
} }
} }
//! [12]
//! [14]
void DtlsServer::shutdown() void DtlsServer::shutdown()
{ {
for (DtlsConnection &connection : knownClients) for (DtlsConnection &connection : knownClients)
@ -248,5 +271,6 @@ void DtlsServer::shutdown()
knownClients.clear(); knownClients.clear();
serverSocket.close(); serverSocket.close();
} }
//! [14]
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -57,12 +57,12 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
//! [0]
class DtlsServer : public QObject class DtlsServer : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
DtlsServer(); DtlsServer();
~DtlsServer(); ~DtlsServer();
@ -71,7 +71,6 @@ public:
void close(); void close();
signals: signals:
void errorMessage(const QString &message); void errorMessage(const QString &message);
void warningMessage(const QString &message); void warningMessage(const QString &message);
void infoMessage(const QString &message); void infoMessage(const QString &message);
@ -80,12 +79,10 @@ signals:
const QByteArray &plainText); const QByteArray &plainText);
private slots: private slots:
void readyRead(); void readyRead();
void pskRequired(QSslPreSharedKeyAuthenticator *auth); void pskRequired(QSslPreSharedKeyAuthenticator *auth);
private: private:
void handleNewConnection(const QHostAddress &peerAddress, quint16 peerPort, void handleNewConnection(const QHostAddress &peerAddress, quint16 peerPort,
const QByteArray &clientHello); const QByteArray &clientHello);
@ -103,6 +100,7 @@ private:
Q_DISABLE_COPY(DtlsServer) Q_DISABLE_COPY(DtlsServer)
}; };
//! [0]
QT_END_NAMESPACE QT_END_NAMESPACE