summaryrefslogtreecommitdiffstats
path: root/examples/network
diff options
context:
space:
mode:
Diffstat (limited to 'examples/network')
-rw-r--r--examples/network/doc/images/secureudpclient-example.pngbin0 -> 23211 bytes
-rw-r--r--examples/network/doc/images/secureudpserver-example.pngbin0 -> 38412 bytes
-rw-r--r--examples/network/doc/src/secureudpclient.qdoc124
-rw-r--r--examples/network/doc/src/secureudpserver.qdoc131
-rw-r--r--examples/network/loopback/dialog.cpp55
-rw-r--r--examples/network/loopback/dialog.h27
-rw-r--r--examples/network/loopback/main.cpp4
-rw-r--r--examples/network/network-chat/client.cpp2
-rw-r--r--examples/network/network-chat/connection.cpp264
-rw-r--r--examples/network/network-chat/connection.h17
-rw-r--r--examples/network/network-chat/peermanager.cpp54
-rw-r--r--examples/network/network-chat/peermanager.h4
-rw-r--r--examples/network/network-chat/server.cpp3
-rw-r--r--examples/network/network.pro7
-rw-r--r--examples/network/secureudpclient/addressdialog.cpp118
-rw-r--r--examples/network/secureudpclient/addressdialog.h85
-rw-r--r--examples/network/secureudpclient/addressdialog.ui132
-rw-r--r--examples/network/secureudpclient/association.cpp197
-rw-r--r--examples/network/secureudpclient/association.h97
-rw-r--r--examples/network/secureudpclient/main.cpp64
-rw-r--r--examples/network/secureudpclient/mainwindow.cpp185
-rw-r--r--examples/network/secureudpclient/mainwindow.h111
-rw-r--r--examples/network/secureudpclient/mainwindow.ui198
-rw-r--r--examples/network/secureudpclient/secureudpclient.pro22
-rw-r--r--examples/network/secureudpserver/main.cpp64
-rw-r--r--examples/network/secureudpserver/mainwindow.cpp138
-rw-r--r--examples/network/secureudpserver/mainwindow.h92
-rw-r--r--examples/network/secureudpserver/mainwindow.ui207
-rw-r--r--examples/network/secureudpserver/nicselector.cpp95
-rw-r--r--examples/network/secureudpserver/nicselector.h84
-rw-r--r--examples/network/secureudpserver/nicselector.ui144
-rw-r--r--examples/network/secureudpserver/secureudpserver.pro21
-rw-r--r--examples/network/secureudpserver/server.cpp277
-rw-r--r--examples/network/secureudpserver/server.h107
34 files changed, 2922 insertions, 208 deletions
diff --git a/examples/network/doc/images/secureudpclient-example.png b/examples/network/doc/images/secureudpclient-example.png
new file mode 100644
index 0000000000..a566aa4ce5
--- /dev/null
+++ b/examples/network/doc/images/secureudpclient-example.png
Binary files differ
diff --git a/examples/network/doc/images/secureudpserver-example.png b/examples/network/doc/images/secureudpserver-example.png
new file mode 100644
index 0000000000..a117b02834
--- /dev/null
+++ b/examples/network/doc/images/secureudpserver-example.png
Binary files differ
diff --git a/examples/network/doc/src/secureudpclient.qdoc b/examples/network/doc/src/secureudpclient.qdoc
new file mode 100644
index 0000000000..dc8538cf85
--- /dev/null
+++ b/examples/network/doc/src/secureudpclient.qdoc
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example secureudpclient
+ \title DTLS client
+ \ingroup examples-network
+ \brief This example demonstrates how to implement client-side DTLS connections.
+
+ \image secureudpclient-example.png Screenshot of the DTLS client example.
+
+ \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
+*/
+
diff --git a/examples/network/doc/src/secureudpserver.qdoc b/examples/network/doc/src/secureudpserver.qdoc
new file mode 100644
index 0000000000..0857f7065f
--- /dev/null
+++ b/examples/network/doc/src/secureudpserver.qdoc
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example secureudpserver
+ \title DTLS server
+ \ingroup examples-network
+ \brief This examples demonstrates how to implement a simple DTLS server.
+
+ \image secureudpserver-example.png Screenshot of the DTLS server example.
+
+ \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
+*/
diff --git a/examples/network/loopback/dialog.cpp b/examples/network/loopback/dialog.cpp
index 99317b9c77..b4e6b0fd5e 100644
--- a/examples/network/loopback/dialog.cpp
+++ b/examples/network/loopback/dialog.cpp
@@ -48,11 +48,11 @@
**
****************************************************************************/
-#include <QtWidgets>
-#include <QtNetwork>
-
#include "dialog.h"
+#include <QtNetwork>
+#include <QtWidgets>
+
static const int TotalBytes = 50 * 1024 * 1024;
static const int PayloadSize = 64 * 1024; // 64 KB
@@ -71,15 +71,15 @@ Dialog::Dialog(QWidget *parent)
buttonBox->addButton(startButton, QDialogButtonBox::ActionRole);
buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);
- connect(startButton, SIGNAL(clicked()), this, SLOT(start()));
- connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));
- connect(&tcpServer, SIGNAL(newConnection()),
- this, SLOT(acceptConnection()));
- connect(&tcpClient, SIGNAL(connected()), this, SLOT(startTransfer()));
- connect(&tcpClient, SIGNAL(bytesWritten(qint64)),
- this, SLOT(updateClientProgress(qint64)));
- connect(&tcpClient, SIGNAL(error(QAbstractSocket::SocketError)),
- this, SLOT(displayError(QAbstractSocket::SocketError)));
+ connect(startButton, &QAbstractButton::clicked, this, &Dialog::start);
+ connect(quitButton, &QAbstractButton::clicked, this, &QWidget::close);
+ connect(&tcpServer, &QTcpServer::newConnection,
+ this, &Dialog::acceptConnection);
+ connect(&tcpClient, &QAbstractSocket::connected, this, &Dialog::startTransfer);
+ connect(&tcpClient, &QIODevice::bytesWritten,
+ this, &Dialog::updateClientProgress);
+ connect(&tcpClient, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
+ this, &Dialog::displayError);
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(clientProgressBar);
@@ -124,10 +124,18 @@ void Dialog::start()
void Dialog::acceptConnection()
{
tcpServerConnection = tcpServer.nextPendingConnection();
- connect(tcpServerConnection, SIGNAL(readyRead()),
- this, SLOT(updateServerProgress()));
- connect(tcpServerConnection, SIGNAL(error(QAbstractSocket::SocketError)),
- this, SLOT(displayError(QAbstractSocket::SocketError)));
+ if (!tcpServerConnection) {
+ serverStatusLabel->setText(tr("Error: got invalid pending connection!"));
+ return;
+ }
+
+ connect(tcpServerConnection, &QIODevice::readyRead,
+ this, &Dialog::updateServerProgress);
+ connect(tcpServerConnection,
+ QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
+ this, &Dialog::displayError);
+ connect(tcpServerConnection, &QTcpSocket::disconnected,
+ tcpServerConnection, &QTcpSocket::deleteLater);
serverStatusLabel->setText(tr("Accepted connection"));
tcpServer.close();
@@ -136,13 +144,13 @@ void Dialog::acceptConnection()
void Dialog::startTransfer()
{
// called when the TCP client connected to the loopback server
- bytesToWrite = TotalBytes - (int)tcpClient.write(QByteArray(PayloadSize, '@'));
+ bytesToWrite = TotalBytes - int(tcpClient.write(QByteArray(PayloadSize, '@')));
clientStatusLabel->setText(tr("Connected"));
}
void Dialog::updateServerProgress()
{
- bytesReceived += (int)tcpServerConnection->bytesAvailable();
+ bytesReceived += int(tcpServerConnection->bytesAvailable());
tcpServerConnection->readAll();
serverProgressBar->setMaximum(TotalBytes);
@@ -161,17 +169,16 @@ void Dialog::updateServerProgress()
void Dialog::updateClientProgress(qint64 numBytes)
{
- // callen when the TCP client has written some bytes
- bytesWritten += (int)numBytes;
+ // called when the TCP client has written some bytes
+ bytesWritten += int(numBytes);
// only write more if not finished and when the Qt write buffer is below a certain size.
- if (bytesToWrite > 0 && tcpClient.bytesToWrite() <= 4*PayloadSize)
- bytesToWrite -= (int)tcpClient.write(QByteArray(qMin(bytesToWrite, PayloadSize), '@'));
+ if (bytesToWrite > 0 && tcpClient.bytesToWrite() <= 4 * PayloadSize)
+ bytesToWrite -= tcpClient.write(QByteArray(qMin(bytesToWrite, PayloadSize), '@'));
clientProgressBar->setMaximum(TotalBytes);
clientProgressBar->setValue(bytesWritten);
- clientStatusLabel->setText(tr("Sent %1MB")
- .arg(bytesWritten / (1024 * 1024)));
+ clientStatusLabel->setText(tr("Sent %1MB").arg(bytesWritten / (1024 * 1024)));
}
void Dialog::displayError(QAbstractSocket::SocketError socketError)
diff --git a/examples/network/loopback/dialog.h b/examples/network/loopback/dialog.h
index b23cfa030b..a70c20550a 100644
--- a/examples/network/loopback/dialog.h
+++ b/examples/network/loopback/dialog.h
@@ -60,9 +60,6 @@ class QDialogButtonBox;
class QLabel;
class QProgressBar;
class QPushButton;
-class QTcpServer;
-class QTcpSocket;
-class QAction;
QT_END_NAMESPACE
class Dialog : public QDialog
@@ -70,7 +67,7 @@ class Dialog : public QDialog
Q_OBJECT
public:
- Dialog(QWidget *parent = 0);
+ Dialog(QWidget *parent = nullptr);
public slots:
void start();
@@ -81,21 +78,21 @@ public slots:
void displayError(QAbstractSocket::SocketError socketError);
private:
- QProgressBar *clientProgressBar;
- QProgressBar *serverProgressBar;
- QLabel *clientStatusLabel;
- QLabel *serverStatusLabel;
+ QProgressBar *clientProgressBar = nullptr;
+ QProgressBar *serverProgressBar = nullptr;
+ QLabel *clientStatusLabel = nullptr;
+ QLabel *serverStatusLabel = nullptr;
- QPushButton *startButton;
- QPushButton *quitButton;
- QDialogButtonBox *buttonBox;
+ QPushButton *startButton = nullptr;
+ QPushButton *quitButton = nullptr;
+ QDialogButtonBox *buttonBox = nullptr;
QTcpServer tcpServer;
QTcpSocket tcpClient;
- QTcpSocket *tcpServerConnection;
- int bytesToWrite;
- int bytesWritten;
- int bytesReceived;
+ QTcpSocket *tcpServerConnection = nullptr;
+ int bytesToWrite = 0;
+ int bytesWritten = 0;
+ int bytesReceived = 0;
};
#endif
diff --git a/examples/network/loopback/main.cpp b/examples/network/loopback/main.cpp
index 9959c472f4..094a11d4fc 100644
--- a/examples/network/loopback/main.cpp
+++ b/examples/network/loopback/main.cpp
@@ -48,10 +48,10 @@
**
****************************************************************************/
-#include <QApplication>
-
#include "dialog.h"
+#include <QApplication>
+
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
diff --git a/examples/network/network-chat/client.cpp b/examples/network/network-chat/client.cpp
index c1eda52a0c..97c2c44b6b 100644
--- a/examples/network/network-chat/client.cpp
+++ b/examples/network/network-chat/client.cpp
@@ -78,7 +78,7 @@ void Client::sendMessage(const QString &message)
QString Client::nickName() const
{
- return QString(peerManager->userName()) + '@' + QHostInfo::localHostName()
+ return peerManager->userName() + '@' + QHostInfo::localHostName()
+ ':' + QString::number(server.serverPort());
}
diff --git a/examples/network/network-chat/connection.cpp b/examples/network/network-chat/connection.cpp
index 332d5dc56b..58cf67eb6d 100644
--- a/examples/network/network-chat/connection.cpp
+++ b/examples/network/network-chat/connection.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -55,17 +56,29 @@
static const int TransferTimeout = 30 * 1000;
static const int PongTimeout = 60 * 1000;
static const int PingInterval = 5 * 1000;
-static const char SeparatorToken = ' ';
+
+/*
+ * Protocol is defined as follows, using the CBOR Data Definition Language:
+ *
+ * protocol = [
+ * greeting, ; must start with a greeting command
+ * * command ; zero or more regular commands after
+ * ]
+ * command = plaintext / ping / pong / greeting
+ * plaintext = { 0 => text }
+ * ping = { 1 => null }
+ * pong = { 2 => null }
+ * greeting = { 3 => text }
+ */
Connection::Connection(QObject *parent)
- : QTcpSocket(parent)
+ : QTcpSocket(parent), writer(this)
{
greetingMessage = tr("undefined");
username = tr("unknown");
state = WaitingForGreeting;
currentDataType = Undefined;
- numBytesForCurrentDataType = -1;
- transferTimerId = 0;
+ transferTimerId = -1;
isGreetingMessageSent = false;
pingTimer.setInterval(PingInterval);
@@ -76,6 +89,22 @@ Connection::Connection(QObject *parent)
this, SLOT(sendGreetingMessage()));
}
+Connection::Connection(qintptr socketDescriptor, QObject *parent)
+ : Connection(parent)
+{
+ setSocketDescriptor(socketDescriptor);
+ reader.setDevice(this);
+}
+
+Connection::~Connection()
+{
+ if (isGreetingMessageSent) {
+ // Indicate clean shutdown.
+ writer.endArray();
+ waitForBytesWritten(2000);
+ }
+}
+
QString Connection::name() const
{
return username;
@@ -91,9 +120,11 @@ bool Connection::sendMessage(const QString &message)
if (message.isEmpty())
return false;
- QByteArray msg = message.toUtf8();
- QByteArray data = "MESSAGE " + QByteArray::number(msg.size()) + ' ' + msg;
- return write(data) == data.size();
+ writer.startMap(1);
+ writer.append(PlainText);
+ writer.append(message);
+ writer.endMap();
+ return true;
}
void Connection::timerEvent(QTimerEvent *timerEvent)
@@ -101,61 +132,75 @@ void Connection::timerEvent(QTimerEvent *timerEvent)
if (timerEvent->timerId() == transferTimerId) {
abort();
killTimer(transferTimerId);
- transferTimerId = 0;
+ transferTimerId = -1;
}
}
void Connection::processReadyRead()
{
- if (state == WaitingForGreeting) {
- if (!readProtocolHeader())
- return;
- if (currentDataType != Greeting) {
- abort();
- return;
+ // we've got more data, let's parse
+ reader.reparse();
+ while (reader.lastError() == QCborError::NoError) {
+ if (state == WaitingForGreeting) {
+ if (!reader.isArray())
+ break; // protocol error
+
+ reader.enterContainer(); // we'll be in this array forever
+ state = ReadingGreeting;
+ } else if (reader.containerDepth() == 1) {
+ // Current state: no command read
+ // Next state: read command ID
+ if (!reader.hasNext()) {
+ reader.leaveContainer();
+ disconnectFromHost();
+ return;
+ }
+
+ if (!reader.isMap() || !reader.isLengthKnown() || reader.length() != 1)
+ break; // protocol error
+ reader.enterContainer();
+ } else if (currentDataType == Undefined) {
+ // Current state: read command ID
+ // Next state: read command payload
+ if (!reader.isInteger())
+ break; // protocol error
+ currentDataType = DataType(reader.toInteger());
+ reader.next();
+ } else {
+ // Current state: read command payload
+ if (reader.isString()) {
+ auto r = reader.readString();
+ buffer += r.data;
+ if (r.status != QCborStreamReader::EndOfString)
+ continue;
+ } else if (reader.isNull()) {
+ reader.next();
+ } else {
+ break; // protocol error
+ }
+
+ // Next state: no command read
+ reader.leaveContainer();
+ if (transferTimerId != -1) {
+ killTimer(transferTimerId);
+ transferTimerId = -1;
+ }
+
+ if (state == ReadingGreeting) {
+ if (currentDataType != Greeting)
+ break; // protocol error
+ processGreeting();
+ } else {
+ processData();
+ }
}
- state = ReadingGreeting;
}
- if (state == ReadingGreeting) {
- if (!hasEnoughData())
- return;
-
- buffer = read(numBytesForCurrentDataType);
- if (buffer.size() != numBytesForCurrentDataType) {
- abort();
- return;
- }
-
- username = QString(buffer) + '@' + peerAddress().toString() + ':'
- + QString::number(peerPort());
- currentDataType = Undefined;
- numBytesForCurrentDataType = 0;
- buffer.clear();
-
- if (!isValid()) {
- abort();
- return;
- }
-
- if (!isGreetingMessageSent)
- sendGreetingMessage();
-
- pingTimer.start();
- pongTime.start();
- state = ReadyForUse;
- emit readyForUse();
- }
+ if (reader.lastError() != QCborError::EndOfFile)
+ abort(); // parse error
- do {
- if (currentDataType == Undefined) {
- if (!readProtocolHeader())
- return;
- }
- if (!hasEnoughData())
- return;
- processData();
- } while (bytesAvailable() > 0);
+ if (transferTimerId != -1 && reader.containerDepth() > 1)
+ transferTimerId = startTimer(TransferTimeout);
}
void Connection::sendPing()
@@ -165,112 +210,58 @@ void Connection::sendPing()
return;
}
- write("PING 1 p");
+ writer.startMap(1);
+ writer.append(Ping);
+ writer.append(nullptr); // no payload
+ writer.endMap();
}
void Connection::sendGreetingMessage()
{
- QByteArray greeting = greetingMessage.toUtf8();
- QByteArray data = "GREETING " + QByteArray::number(greeting.size()) + ' ' + greeting;
- if (write(data) == data.size())
- isGreetingMessageSent = true;
-}
+ writer.startArray(); // this array never ends
-int Connection::readDataIntoBuffer(int maxSize)
-{
- if (maxSize > MaxBufferSize)
- return 0;
+ writer.startMap(1);
+ writer.append(Greeting);
+ writer.append(greetingMessage);
+ writer.endMap();
+ isGreetingMessageSent = true;
- int numBytesBeforeRead = buffer.size();
- if (numBytesBeforeRead == MaxBufferSize) {
- abort();
- return 0;
- }
-
- while (bytesAvailable() > 0 && buffer.size() < maxSize) {
- buffer.append(read(1));
- if (buffer.endsWith(SeparatorToken))
- break;
- }
- return buffer.size() - numBytesBeforeRead;
+ if (!reader.device())
+ reader.setDevice(this);
}
-int Connection::dataLengthForCurrentDataType()
+void Connection::processGreeting()
{
- if (bytesAvailable() <= 0 || readDataIntoBuffer() <= 0
- || !buffer.endsWith(SeparatorToken))
- return 0;
-
- buffer.chop(1);
- int number = buffer.toInt();
+ username = buffer + '@' + peerAddress().toString() + ':'
+ + QString::number(peerPort());
+ currentDataType = Undefined;
buffer.clear();
- return number;
-}
-
-bool Connection::readProtocolHeader()
-{
- if (transferTimerId) {
- killTimer(transferTimerId);
- transferTimerId = 0;
- }
-
- if (readDataIntoBuffer() <= 0) {
- transferTimerId = startTimer(TransferTimeout);
- return false;
- }
- if (buffer == "PING ") {
- currentDataType = Ping;
- } else if (buffer == "PONG ") {
- currentDataType = Pong;
- } else if (buffer == "MESSAGE ") {
- currentDataType = PlainText;
- } else if (buffer == "GREETING ") {
- currentDataType = Greeting;
- } else {
- currentDataType = Undefined;
+ if (!isValid()) {
abort();
- return false;
- }
-
- buffer.clear();
- numBytesForCurrentDataType = dataLengthForCurrentDataType();
- return true;
-}
-
-bool Connection::hasEnoughData()
-{
- if (transferTimerId) {
- QObject::killTimer(transferTimerId);
- transferTimerId = 0;
+ return;
}
- if (numBytesForCurrentDataType <= 0)
- numBytesForCurrentDataType = dataLengthForCurrentDataType();
-
- if (bytesAvailable() < numBytesForCurrentDataType
- || numBytesForCurrentDataType <= 0) {
- transferTimerId = startTimer(TransferTimeout);
- return false;
- }
+ if (!isGreetingMessageSent)
+ sendGreetingMessage();
- return true;
+ pingTimer.start();
+ pongTime.start();
+ state = ReadyForUse;
+ emit readyForUse();
}
void Connection::processData()
{
- buffer = read(numBytesForCurrentDataType);
- if (buffer.size() != numBytesForCurrentDataType) {
- abort();
- return;
- }
-
switch (currentDataType) {
case PlainText:
- emit newMessage(username, QString::fromUtf8(buffer));
+ emit newMessage(username, buffer);
break;
case Ping:
- write("PONG 1 p");
+ writer.startMap(1);
+ writer.append(Pong);
+ writer.append(nullptr); // no payload
+ writer.endMap();
break;
case Pong:
pongTime.restart();
@@ -280,6 +271,5 @@ void Connection::processData()
}
currentDataType = Undefined;
- numBytesForCurrentDataType = 0;
buffer.clear();
}
diff --git a/examples/network/network-chat/connection.h b/examples/network/network-chat/connection.h
index 67d25d4d1e..fa0671a522 100644
--- a/examples/network/network-chat/connection.h
+++ b/examples/network/network-chat/connection.h
@@ -51,10 +51,12 @@
#ifndef CONNECTION_H
#define CONNECTION_H
+#include <QCborStreamReader>
+#include <QCborStreamWriter>
+#include <QElapsedTimer>
#include <QHostAddress>
#include <QString>
#include <QTcpSocket>
-#include <QTime>
#include <QTimer>
static const int MaxBufferSize = 1024000;
@@ -78,6 +80,8 @@ public:
};
Connection(QObject *parent = 0);
+ Connection(qintptr socketDescriptor, QObject *parent = 0);
+ ~Connection();
QString name() const;
void setGreetingMessage(const QString &message);
@@ -96,20 +100,19 @@ private slots:
void sendGreetingMessage();
private:
- int readDataIntoBuffer(int maxSize = MaxBufferSize);
- int dataLengthForCurrentDataType();
- bool readProtocolHeader();
bool hasEnoughData();
+ void processGreeting();
void processData();
+ QCborStreamReader reader;
+ QCborStreamWriter writer;
QString greetingMessage;
QString username;
QTimer pingTimer;
- QTime pongTime;
- QByteArray buffer;
+ QElapsedTimer pongTime;
+ QString buffer;
ConnectionState state;
DataType currentDataType;
- int numBytesForCurrentDataType;
int transferTimerId;
bool isGreetingMessageSent;
};
diff --git a/examples/network/network-chat/peermanager.cpp b/examples/network/network-chat/peermanager.cpp
index c70cc5e56d..38fa2e8e50 100644
--- a/examples/network/network-chat/peermanager.cpp
+++ b/examples/network/network-chat/peermanager.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2018 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
@@ -62,16 +63,14 @@ PeerManager::PeerManager(Client *client)
{
this->client = client;
- QStringList envVariables;
- envVariables << "USERNAME" << "USER" << "USERDOMAIN"
- << "HOSTNAME" << "DOMAINNAME";
+ static const char *envVariables[] = {
+ "USERNAME", "USER", "USERDOMAIN", "HOSTNAME", "DOMAINNAME"
+ };
- QProcessEnvironment environment = QProcessEnvironment::systemEnvironment();
- foreach (QString string, envVariables) {
- if (environment.contains(string)) {
- username = environment.value(string).toUtf8();
+ for (const char *varname : envVariables) {
+ username = qEnvironmentVariable(varname);
+ if (!username.isNull())
break;
- }
}
if (username.isEmpty())
@@ -95,7 +94,7 @@ void PeerManager::setServerPort(int port)
serverPort = port;
}
-QByteArray PeerManager::userName() const
+QString PeerManager::userName() const
{
return username;
}
@@ -108,7 +107,7 @@ void PeerManager::startBroadcasting()
bool PeerManager::isLocalHostAddress(const QHostAddress &address)
{
foreach (QHostAddress localAddress, ipAddresses) {
- if (address == localAddress)
+ if (address.isEqual(localAddress))
return true;
}
return false;
@@ -116,9 +115,14 @@ bool PeerManager::isLocalHostAddress(const QHostAddress &address)
void PeerManager::sendBroadcastDatagram()
{
- QByteArray datagram(username);
- datagram.append('@');
- datagram.append(QByteArray::number(serverPort));
+ QByteArray datagram;
+ {
+ QCborStreamWriter writer(&datagram);
+ writer.startArray(2);
+ writer.append(username);
+ writer.append(serverPort);
+ writer.endArray();
+ }
bool validBroadcastAddresses = true;
foreach (QHostAddress address, broadcastAddresses) {
@@ -142,11 +146,27 @@ void PeerManager::readBroadcastDatagram()
&senderIp, &senderPort) == -1)
continue;
- QList<QByteArray> list = datagram.split('@');
- if (list.size() != 2)
- continue;
+ int senderServerPort;
+ {
+ // decode the datagram
+ QCborStreamReader reader(datagram);
+ if (reader.lastError() != QCborError::NoError || !reader.isArray())
+ continue;
+ if (!reader.isLengthKnown() || reader.length() != 2)
+ continue;
+
+ reader.enterContainer();
+ if (reader.lastError() != QCborError::NoError || !reader.isString())
+ continue;
+ while (reader.readString().status == QCborStreamReader::Ok) {
+ // we don't actually need the username right now
+ }
+
+ if (reader.lastError() != QCborError::NoError || !reader.isUnsignedInteger())
+ continue;
+ senderServerPort = reader.toInteger();
+ }
- int senderServerPort = list.at(1).toInt();
if (isLocalHostAddress(senderIp) && senderServerPort == serverPort)
continue;
diff --git a/examples/network/network-chat/peermanager.h b/examples/network/network-chat/peermanager.h
index 0bcd67579c..b79028235b 100644
--- a/examples/network/network-chat/peermanager.h
+++ b/examples/network/network-chat/peermanager.h
@@ -68,7 +68,7 @@ public:
PeerManager(Client *client);
void setServerPort(int port);
- QByteArray userName() const;
+ QString userName() const;
void startBroadcasting();
bool isLocalHostAddress(const QHostAddress &address);
@@ -87,7 +87,7 @@ private:
QList<QHostAddress> ipAddresses;
QUdpSocket broadcastSocket;
QTimer broadcastTimer;
- QByteArray username;
+ QString username;
int serverPort;
};
diff --git a/examples/network/network-chat/server.cpp b/examples/network/network-chat/server.cpp
index cc154728d5..b3e4a07f60 100644
--- a/examples/network/network-chat/server.cpp
+++ b/examples/network/network-chat/server.cpp
@@ -61,7 +61,6 @@ Server::Server(QObject *parent)
void Server::incomingConnection(qintptr socketDescriptor)
{
- Connection *connection = new Connection(this);
- connection->setSocketDescriptor(socketDescriptor);
+ Connection *connection = new Connection(socketDescriptor, this);
emit newConnection(connection);
}
diff --git a/examples/network/network.pro b/examples/network/network.pro
index d64b16c760..93049014eb 100644
--- a/examples/network/network.pro
+++ b/examples/network/network.pro
@@ -29,7 +29,12 @@ qtHaveModule(widgets) {
}
- qtConfig(openssl): SUBDIRS += securesocketclient
+ qtConfig(openssl) {
+ SUBDIRS += \
+ securesocketclient \
+ secureudpserver \
+ secureudpclient
+ }
qtConfig(sctp): SUBDIRS += multistreamserver multistreamclient
}
diff --git a/examples/network/secureudpclient/addressdialog.cpp b/examples/network/secureudpclient/addressdialog.cpp
new file mode 100644
index 0000000000..ccb58c853c
--- /dev/null
+++ b/examples/network/secureudpclient/addressdialog.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "addressdialog.h"
+#include "ui_addressdialog.h"
+
+#include <QtCore>
+#include <QtNetwork>
+#include <QtWidgets>
+
+#include <limits>
+
+AddressDialog::AddressDialog(QWidget *parent)
+ : QDialog(parent),
+ ui(new Ui::AddressDialog)
+{
+ ui->setupUi(this);
+ setupHostSelector();
+ setupPortSelector();
+}
+
+AddressDialog::~AddressDialog()
+{
+ delete ui;
+}
+
+QString AddressDialog::remoteName() const
+{
+ if (ui->addressSelector->count())
+ return ui->addressSelector->currentText();
+ return {};
+}
+
+quint16 AddressDialog::remotePort() const
+{
+ return quint16(ui->portSelector->text().toUInt());
+}
+
+void AddressDialog::setupHostSelector()
+{
+ QString name(QHostInfo::localHostName());
+ if (!name.isEmpty()) {
+ ui->addressSelector->addItem(name);
+ const QString domain = QHostInfo::localDomainName();
+ if (!domain.isEmpty())
+ ui->addressSelector->addItem(name + QChar('.') + domain);
+ }
+
+ if (name != QStringLiteral("localhost"))
+ ui->addressSelector->addItem(QStringLiteral("localhost"));
+
+ const QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
+ for (const QHostAddress &ipAddress : ipAddressesList) {
+ if (!ipAddress.isLoopback())
+ ui->addressSelector->addItem(ipAddress.toString());
+ }
+
+ ui->addressSelector->insertSeparator(ui->addressSelector->count());
+
+ for (const QHostAddress &ipAddress : ipAddressesList) {
+ if (ipAddress.isLoopback())
+ ui->addressSelector->addItem(ipAddress.toString());
+ }
+}
+
+void AddressDialog::setupPortSelector()
+{
+ ui->portSelector->setValidator(new QIntValidator(0, std::numeric_limits<quint16>::max(),
+ ui->portSelector));
+ ui->portSelector->setText(QStringLiteral("22334"));
+}
diff --git a/examples/network/secureudpclient/addressdialog.h b/examples/network/secureudpclient/addressdialog.h
new file mode 100644
index 0000000000..43792faa4b
--- /dev/null
+++ b/examples/network/secureudpclient/addressdialog.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef ADDRESSDIALOG_H
+#define ADDRESSDIALOG_H
+
+#include <QDialog>
+
+QT_BEGIN_NAMESPACE
+
+namespace Ui {
+
+class AddressDialog;
+
+}
+
+QT_END_NAMESPACE
+
+QT_USE_NAMESPACE
+
+class AddressDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit AddressDialog(QWidget *parent = nullptr);
+ ~AddressDialog();
+
+ QString remoteName() const;
+ quint16 remotePort() const;
+
+private:
+ void setupHostSelector();
+ void setupPortSelector();
+
+ Ui::AddressDialog *ui = nullptr;
+};
+
+#endif // ADDRESSDIALOG_H
diff --git a/examples/network/secureudpclient/addressdialog.ui b/examples/network/secureudpclient/addressdialog.ui
new file mode 100644
index 0000000000..a7d9bdc253
--- /dev/null
+++ b/examples/network/secureudpclient/addressdialog.ui
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AddressDialog</class>
+ <widget class="QDialog" name="AddressDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>548</width>
+ <height>143</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Host info</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Host name (server's address):</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="addressSelector">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>320</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>320</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ <property name="frame">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Server port:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="portSelector">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>320</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>320</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>AddressDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>AddressDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/network/secureudpclient/association.cpp b/examples/network/secureudpclient/association.cpp
new file mode 100644
index 0000000000..c950260078
--- /dev/null
+++ b/examples/network/secureudpclient/association.cpp
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "association.h"
+
+QT_BEGIN_NAMESPACE
+
+DtlsAssociation::DtlsAssociation(const QHostAddress &address, quint16 port,
+ const QString &connectionName)
+ : name(connectionName),
+ crypto(QSslSocket::SslClientMode)
+{
+ //! [1]
+ auto configuration = QSslConfiguration::defaultDtlsConfiguration();
+ configuration.setPeerVerifyMode(QSslSocket::VerifyNone);
+ crypto.setPeer(address, port);
+ crypto.setDtlsConfiguration(configuration);
+ //! [1]
+
+ //! [2]
+ connect(&crypto, &QDtls::handshakeTimeout, this, &DtlsAssociation::handshakeTimeout);
+ //! [2]
+ connect(&crypto, &QDtls::pskRequired, this, &DtlsAssociation::pskRequired);
+ //! [3]
+ socket.connectToHost(address.toString(), port);
+ //! [3]
+ //! [13]
+ connect(&socket, &QUdpSocket::readyRead, this, &DtlsAssociation::readyRead);
+ //! [13]
+ //! [4]
+ pingTimer.setInterval(5000);
+ connect(&pingTimer, &QTimer::timeout, this, &DtlsAssociation::pingTimeout);
+ //! [4]
+}
+
+//! [12]
+DtlsAssociation::~DtlsAssociation()
+{
+ if (crypto.isConnectionEncrypted())
+ crypto.shutdown(&socket);
+}
+//! [12]
+
+//! [5]
+void DtlsAssociation::startHandshake()
+{
+ if (socket.state() != QAbstractSocket::ConnectedState) {
+ emit infoMessage(tr("%1: connecting UDP socket first ...").arg(name));
+ connect(&socket, &QAbstractSocket::connected, this, &DtlsAssociation::udpSocketConnected);
+ return;
+ }
+
+ if (!crypto.doHandshake(&socket))
+ emit errorMessage(tr("%1: failed to start a handshake - %2").arg(name, crypto.dtlsErrorString()));
+ else
+ emit infoMessage(tr("%1: starting a handshake").arg(name));
+}
+//! [5]
+
+void DtlsAssociation::udpSocketConnected()
+{
+ emit infoMessage(tr("%1: UDP socket is now in ConnectedState, continue with handshake ...").arg(name));
+ startHandshake();
+}
+
+void DtlsAssociation::readyRead()
+{
+ //! [6]
+ QByteArray dgram(socket.pendingDatagramSize(), Qt::Uninitialized);
+ const qint64 bytesRead = socket.readDatagram(dgram.data(), dgram.size());
+ if (bytesRead <= 0) {
+ emit warningMessage(tr("%1: spurious read notification?").arg(name));
+ return;
+ }
+
+ dgram.resize(bytesRead);
+ //! [6]
+ //! [7]
+ if (crypto.isConnectionEncrypted()) {
+ const QByteArray plainText = crypto.decryptDatagram(&socket, dgram);
+ if (plainText.size()) {
+ emit serverResponse(name, dgram, plainText);
+ return;
+ }
+
+ if (crypto.dtlsError() == QDtlsError::RemoteClosedConnectionError) {
+ emit errorMessage(tr("%1: shutdown alert received").arg(name));
+ socket.close();
+ pingTimer.stop();
+ return;
+ }
+
+ emit warningMessage(tr("%1: zero-length datagram received?").arg(name));
+ } else {
+ //! [7]
+ //! [8]
+ if (!crypto.doHandshake(&socket, dgram)) {
+ emit errorMessage(tr("%1: handshake error - %2").arg(name, crypto.dtlsErrorString()));
+ return;
+ }
+ //! [8]
+
+ //! [9]
+ if (crypto.isConnectionEncrypted()) {
+ emit infoMessage(tr("%1: encrypted connection established!").arg(name));
+ pingTimer.start();
+ pingTimeout();
+ } else {
+ //! [9]
+ emit infoMessage(tr("%1: continuing with handshake ...").arg(name));
+ }
+ }
+}
+
+//! [11]
+void DtlsAssociation::handshakeTimeout()
+{
+ emit warningMessage(tr("%1: handshake timeout, trying to re-transmit").arg(name));
+ if (!crypto.handleTimeout(&socket))
+ emit errorMessage(tr("%1: failed to re-transmit - %2").arg(name, crypto.dtlsErrorString()));
+}
+//! [11]
+
+//! [14]
+void DtlsAssociation::pskRequired(QSslPreSharedKeyAuthenticator *auth)
+{
+ Q_ASSERT(auth);
+
+ emit infoMessage(tr("%1: providing pre-shared key ...").arg(name));
+ auth->setIdentity(name.toLatin1());
+ auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f"));
+}
+//! [14]
+
+//! [10]
+void DtlsAssociation::pingTimeout()
+{
+ static const QString message = QStringLiteral("I am %1, please, accept our ping %2");
+ const qint64 written = crypto.writeDatagramEncrypted(&socket, message.arg(name).arg(ping).toLatin1());
+ if (written <= 0) {
+ emit errorMessage(tr("%1: failed to send a ping - %2").arg(name, crypto.dtlsErrorString()));
+ pingTimer.stop();
+ return;
+ }
+
+ ++ping;
+}
+//! [10]
+
+QT_END_NAMESPACE
diff --git a/examples/network/secureudpclient/association.h b/examples/network/secureudpclient/association.h
new file mode 100644
index 0000000000..be89ce695e
--- /dev/null
+++ b/examples/network/secureudpclient/association.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef ASSOCIATION_H
+#define ASSOCIATION_H
+
+#include <QtNetwork>
+#include <QtCore>
+
+QT_BEGIN_NAMESPACE
+
+//! [0]
+class DtlsAssociation : public QObject
+{
+ Q_OBJECT
+
+public:
+ DtlsAssociation(const QHostAddress &address, quint16 port,
+ const QString &connectionName);
+ ~DtlsAssociation();
+ void startHandshake();
+
+signals:
+ void errorMessage(const QString &message);
+ void warningMessage(const QString &message);
+ void infoMessage(const QString &message);
+ void serverResponse(const QString &clientInfo, const QByteArray &datagraam,
+ const QByteArray &plainText);
+
+private slots:
+ void udpSocketConnected();
+ void readyRead();
+ void handshakeTimeout();
+ void pskRequired(QSslPreSharedKeyAuthenticator *auth);
+ void pingTimeout();
+
+private:
+ QString name;
+ QUdpSocket socket;
+ QDtls crypto;
+
+ QTimer pingTimer;
+ unsigned ping = 0;
+
+ Q_DISABLE_COPY(DtlsAssociation)
+};
+//! [0]
+
+QT_END_NAMESPACE
+
+#endif // ASSOCIATION_H
diff --git a/examples/network/secureudpclient/main.cpp b/examples/network/secureudpclient/main.cpp
new file mode 100644
index 0000000000..2cf35878f2
--- /dev/null
+++ b/examples/network/secureudpclient/main.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QT_USE_NAMESPACE
+
+ QApplication app(argc, argv);
+ MainWindow window;
+ window.show();
+
+ return app.exec();
+}
diff --git a/examples/network/secureudpclient/mainwindow.cpp b/examples/network/secureudpclient/mainwindow.cpp
new file mode 100644
index 0000000000..2fbf757c81
--- /dev/null
+++ b/examples/network/secureudpclient/mainwindow.cpp
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore>
+#include <QtNetwork>
+
+#include "addressdialog.h"
+#include "association.h"
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+#include <utility>
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent),
+ ui(new Ui::MainWindow),
+ nameTemplate(QStringLiteral("Alice (clone number %1)"))
+{
+ ui->setupUi(this);
+ updateUi();
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
+//! [0]
+
+const QString colorizer(QStringLiteral("<font color=\"%1\">%2</font><br>"));
+
+void MainWindow::addErrorMessage(const QString &message)
+{
+ ui->clientMessages->insertHtml(colorizer.arg(QStringLiteral("Crimson"), message));
+}
+
+void MainWindow::addWarningMessage(const QString &message)
+{
+ ui->clientMessages->insertHtml(colorizer.arg(QStringLiteral("DarkOrange"), message));
+}
+
+void MainWindow::addInfoMessage(const QString &message)
+{
+ ui->clientMessages->insertHtml(colorizer.arg(QStringLiteral("DarkBlue"), message));
+}
+
+void MainWindow::addServerResponse(const QString &clientInfo, const QByteArray &datagram,
+ const QByteArray &plainText)
+{
+ static const QString messageColor = QStringLiteral("DarkMagenta");
+ static const QString formatter = QStringLiteral("<br>---------------"
+ "<br>%1 received a DTLS datagram:<br> %2"
+ "<br>As plain text:<br> %3");
+
+ const QString html = formatter.arg(clientInfo, QString::fromUtf8(datagram.toHex(' ')),
+ QString::fromUtf8(plainText));
+ ui->serverMessages->insertHtml(colorizer.arg(messageColor, html));
+}
+
+//! [0]
+
+void MainWindow::on_connectButton_clicked()
+{
+ if (lookupId != -1) {
+ QHostInfo::abortHostLookup(lookupId);
+ lookupId = -1;
+ port = 0;
+ updateUi();
+ return;
+ }
+
+ AddressDialog dialog;
+ if (dialog.exec() != QDialog::Accepted)
+ return;
+
+ const QString hostName = dialog.remoteName();
+ if (hostName.isEmpty())
+ return addWarningMessage(tr("Host name or address required to connect"));
+
+ port = dialog.remotePort();
+ QHostAddress remoteAddress;
+ if (remoteAddress.setAddress(hostName))
+ return startNewConnection(remoteAddress);
+
+ addInfoMessage(tr("Looking up the host ..."));
+ lookupId = QHostInfo::lookupHost(hostName, this, SLOT(lookupFinished(QHostInfo)));
+ updateUi();
+}
+
+void MainWindow::updateUi()
+{
+ ui->connectButton->setText(lookupId == -1 ? tr("Connect ...") : tr("Cancel lookup"));
+ ui->shutdownButton->setEnabled(connections.size() != 0);
+}
+
+void MainWindow::lookupFinished(const QHostInfo &hostInfo)
+{
+ if (hostInfo.lookupId() != lookupId)
+ return;
+
+ lookupId = -1;
+ updateUi();
+
+ if (hostInfo.error() != QHostInfo::NoError) {
+ addErrorMessage(hostInfo.errorString());
+ return;
+ }
+
+ const QList<QHostAddress> foundAddresses = hostInfo.addresses();
+ if (foundAddresses.empty()) {
+ addWarningMessage(tr("Host not found"));
+ return;
+ }
+
+ const auto remoteAddress = foundAddresses.at(0);
+ addInfoMessage(tr("Connecting to: %1").arg(remoteAddress.toString()));
+ startNewConnection(remoteAddress);
+}
+
+void MainWindow::startNewConnection(const QHostAddress &address)
+{
+ AssocPtr newConnection(new DtlsAssociation(address, port, nameTemplate.arg(nextId)));
+ connect(newConnection.data(), &DtlsAssociation::errorMessage, this, &MainWindow::addErrorMessage);
+ connect(newConnection.data(), &DtlsAssociation::warningMessage, this, &MainWindow::addWarningMessage);
+ connect(newConnection.data(), &DtlsAssociation::infoMessage, this, &MainWindow::addInfoMessage);
+ connect(newConnection.data(), &DtlsAssociation::serverResponse, this, &MainWindow::addServerResponse);
+ connections.push_back(std::move(newConnection));
+ connections.back()->startHandshake();
+ updateUi();
+
+ ++nextId;
+}
+
+void MainWindow::on_shutdownButton_clicked()
+{
+ connections.clear();
+ updateUi();
+}
diff --git a/examples/network/secureudpclient/mainwindow.h b/examples/network/secureudpclient/mainwindow.h
new file mode 100644
index 0000000000..0d443fd376
--- /dev/null
+++ b/examples/network/secureudpclient/mainwindow.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QSharedPointer>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+
+namespace Ui {
+
+class MainWindow;
+
+}
+
+class QHostAddress;
+class QHostInfo;
+
+class DtlsAssociation;
+
+QT_END_NAMESPACE
+
+QT_USE_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+private slots:
+
+ void addErrorMessage(const QString &message);
+ void addWarningMessage(const QString &message);
+ void addInfoMessage(const QString &message);
+ void addServerResponse(const QString &clientInfo, const QByteArray &datagram,
+ const QByteArray &plainText);
+
+ void on_connectButton_clicked();
+ void on_shutdownButton_clicked();
+
+ void lookupFinished(const QHostInfo &hostInfo);
+
+private:
+ void updateUi();
+ void startNewConnection(const QHostAddress &address);
+
+ Ui::MainWindow *ui = nullptr;
+
+ using AssocPtr = QSharedPointer<DtlsAssociation>;
+ QVector<AssocPtr> connections;
+
+ QString nameTemplate;
+ unsigned nextId = 0;
+
+ quint16 port = 0;
+ int lookupId = -1;
+};
+
+#endif // MAINWINDOW_H
diff --git a/examples/network/secureudpclient/mainwindow.ui b/examples/network/secureudpclient/mainwindow.ui
new file mode 100644
index 0000000000..59a31974ee
--- /dev/null
+++ b/examples/network/secureudpclient/mainwindow.ui
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1200</width>
+ <height>550</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>1200</width>
+ <height>550</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>1200</width>
+ <height>550</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>DTLS client</string>
+ </property>
+ <widget class="QWidget" name="centralwidget">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>590</width>
+ <height>400</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>DTLS info messages:</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <widget class="QTextEdit" name="clientMessages">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>30</y>
+ <width>570</width>
+ <height>360</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>570</width>
+ <height>360</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>570</width>
+ <height>360</height>
+ </size>
+ </property>
+ <property name="acceptDrops">
+ <bool>false</bool>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QPushButton" name="connectButton">
+ <property name="text">
+ <string>Connect ...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="shutdownButton">
+ <property name="text">
+ <string>Shutdown connections</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="minimumSize">
+ <size>
+ <width>580</width>
+ <height>490</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>580</width>
+ <height>490</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Received datagrams:</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <widget class="QTextEdit" name="serverMessages">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>30</y>
+ <width>560</width>
+ <height>450</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>560</width>
+ <height>450</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>560</width>
+ <height>450</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menubar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1200</width>
+ <height>22</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QStatusBar" name="statusbar"/>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/network/secureudpclient/secureudpclient.pro b/examples/network/secureudpclient/secureudpclient.pro
new file mode 100644
index 0000000000..44e4200994
--- /dev/null
+++ b/examples/network/secureudpclient/secureudpclient.pro
@@ -0,0 +1,22 @@
+QT += widgets network
+
+TARGET = secureudpclient
+TEMPLATE = app
+
+SOURCES += \
+ main.cpp \
+ association.cpp \
+ mainwindow.cpp \
+ addressdialog.cpp
+
+HEADERS += \
+ association.h \
+ mainwindow.h \
+ addressdialog.h
+
+FORMS += \
+ mainwindow.ui \
+ addressdialog.ui
+
+target.path = $$[QT_INSTALL_EXAMPLES]/network/secureudpclient
+INSTALLS += target
diff --git a/examples/network/secureudpserver/main.cpp b/examples/network/secureudpserver/main.cpp
new file mode 100644
index 0000000000..1a29d9d7ec
--- /dev/null
+++ b/examples/network/secureudpserver/main.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+
+#include "mainwindow.h"
+
+int main(int argc, char *argv[])
+{
+ QT_USE_NAMESPACE
+
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+
+ return a.exec();
+}
diff --git a/examples/network/secureudpserver/mainwindow.cpp b/examples/network/secureudpserver/mainwindow.cpp
new file mode 100644
index 0000000000..ef1974c311
--- /dev/null
+++ b/examples/network/secureudpserver/mainwindow.cpp
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+#include "nicselector.h"
+#include "ui_mainwindow.h"
+
+MainWindow::MainWindow()
+ : ui(new Ui::MainWindow)
+{
+ ui->setupUi(this);
+
+ connect(&server, &DtlsServer::errorMessage, this, &MainWindow::addErrorMessage);
+ connect(&server, &DtlsServer::warningMessage, this, &MainWindow::addWarningMessage);
+ connect(&server, &DtlsServer::infoMessage, this, &MainWindow::addInfoMessage);
+ connect(&server, &DtlsServer::datagramReceived, this, &MainWindow::addClientMessage);
+
+ updateUi();
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
+void MainWindow::on_startButton_clicked()
+{
+ if (!server.isListening()) {
+ NicSelector ipDialog;
+ if (ipDialog.exec() == QDialog::Accepted) {
+ const QHostAddress address = ipDialog.selectedIp();
+ const quint16 port = ipDialog.selectedPort();
+ if (address.isNull()) {
+ addErrorMessage(tr("Failed to start listening, no valid address/port"));
+ } else if (server.listen(address, port)) {
+ addInfoMessage(tr("Server is listening on address %1 and port %2")
+ .arg(address.toString())
+ .arg(port));
+ }
+ }
+ } else {
+ server.close();
+ addInfoMessage(tr("Server is not accepting new connections"));
+ }
+
+ updateUi();
+}
+
+void MainWindow::on_quitButton_clicked()
+{
+ QCoreApplication::exit(0);
+}
+
+void MainWindow::updateUi()
+{
+ server.isListening() ? ui->startButton->setText(tr("Stop listening"))
+ : ui->startButton->setText(tr("Start listening"));
+}
+
+//! [0]
+const QString colorizer(QStringLiteral("<font color=\"%1\">%2</font><br>"));
+
+void MainWindow::addErrorMessage(const QString &message)
+{
+ ui->serverInfo->insertHtml(colorizer.arg(QStringLiteral("Crimson"), message));
+}
+
+void MainWindow::addWarningMessage(const QString &message)
+{
+ ui->serverInfo->insertHtml(colorizer.arg(QStringLiteral("DarkOrange"), message));
+}
+
+void MainWindow::addInfoMessage(const QString &message)
+{
+ ui->serverInfo->insertHtml(colorizer.arg(QStringLiteral("DarkBlue"), message));
+}
+
+void MainWindow::addClientMessage(const QString &peerInfo, const QByteArray &datagram,
+ const QByteArray &plainText)
+{
+ static const QString messageColor = QStringLiteral("DarkMagenta");
+ static const QString formatter = QStringLiteral("<br>---------------"
+ "<br>A message from %1"
+ "<br>DTLS datagram:<br> %2"
+ "<br>As plain text:<br> %3");
+
+ const QString html = formatter.arg(peerInfo, QString::fromUtf8(datagram.toHex(' ')),
+ QString::fromUtf8(plainText));
+ ui->messages->insertHtml(colorizer.arg(messageColor, html));
+}
+//! [0]
diff --git a/examples/network/secureudpserver/mainwindow.h b/examples/network/secureudpserver/mainwindow.h
new file mode 100644
index 0000000000..b39d984d50
--- /dev/null
+++ b/examples/network/secureudpserver/mainwindow.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include "server.h"
+
+#include <QMainWindow>
+
+QT_BEGIN_NAMESPACE
+
+namespace Ui {
+class MainWindow;
+}
+
+QT_END_NAMESPACE
+
+QT_USE_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow();
+ ~MainWindow();
+
+private slots:
+ void addErrorMessage(const QString &message);
+ void addWarningMessage(const QString &message);
+ void addInfoMessage(const QString &message);
+ void addClientMessage(const QString &peerInfo, const QByteArray &datagram,
+ const QByteArray &plainText);
+
+ void on_startButton_clicked();
+ void on_quitButton_clicked();
+
+private:
+ void updateUi();
+
+ Ui::MainWindow *ui = nullptr;
+ DtlsServer server;
+};
+
+#endif // MAINWINDOW_H
diff --git a/examples/network/secureudpserver/mainwindow.ui b/examples/network/secureudpserver/mainwindow.ui
new file mode 100644
index 0000000000..e25e19921b
--- /dev/null
+++ b/examples/network/secureudpserver/mainwindow.ui
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1090</width>
+ <height>670</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>1090</width>
+ <height>670</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>1090</width>
+ <height>670</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>DTLS server</string>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <widget class="QWidget" name="layoutWidget">
+ <property name="geometry">
+ <rect>
+ <x>20</x>
+ <y>20</y>
+ <width>1050</width>
+ <height>576</height>
+ </rect>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QGroupBox" name="infoBox">
+ <property name="minimumSize">
+ <size>
+ <width>520</width>
+ <height>540</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>520</width>
+ <height>540</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Dtls server info:</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <widget class="QTextEdit" name="serverInfo">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>30</y>
+ <width>500</width>
+ <height>500</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>500</width>
+ <height>500</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>500</width>
+ <height>500</height>
+ </size>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="minimumSize">
+ <size>
+ <width>520</width>
+ <height>540</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>520</width>
+ <height>540</height>
+ </size>
+ </property>
+ <property name="title">
+ <string>Received messages:</string>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ <widget class="QTextEdit" name="messages">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>30</y>
+ <width>500</width>
+ <height>500</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>500</width>
+ <height>500</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>500</width>
+ <height>500</height>
+ </size>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="startButton">
+ <property name="text">
+ <string>Start listening</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="quitButton">
+ <property name="text">
+ <string>Quit</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <widget class="QMenuBar" name="menuBar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1090</width>
+ <height>22</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QToolBar" name="mainToolBar">
+ <attribute name="toolBarArea">
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ <widget class="QStatusBar" name="statusBar"/>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/examples/network/secureudpserver/nicselector.cpp b/examples/network/secureudpserver/nicselector.cpp
new file mode 100644
index 0000000000..ea26439d74
--- /dev/null
+++ b/examples/network/secureudpserver/nicselector.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <limits>
+
+#include <QtCore>
+#include <QtNetwork>
+
+#include "nicselector.h"
+#include "ui_nicselector.h"
+
+NicSelector::NicSelector(QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::NicSelector)
+{
+ ui->setupUi(this);
+ auto portValidator = new QIntValidator(0, int(std::numeric_limits<quint16>::max()),
+ ui->portSelector);
+ ui->portSelector->setValidator(portValidator);
+ ui->portSelector->setText(QStringLiteral("22334"));
+
+ const QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
+ availableAddresses.reserve(ipAddressesList.size());
+ for (const QHostAddress &ip : ipAddressesList) {
+ if (ip != QHostAddress::LocalHost && ip.toIPv4Address()) {
+ availableAddresses.push_back(ip);
+ ui->ipSelector->addItem(ip.toString());
+ }
+ }
+}
+
+NicSelector::~NicSelector()
+{
+ delete ui;
+}
+
+QHostAddress NicSelector::selectedIp() const
+{
+ if (!availableAddresses.size())
+ return {};
+
+ return availableAddresses[ui->ipSelector->currentIndex()];
+}
+
+quint16 NicSelector::selectedPort() const
+{
+ return quint16(ui->portSelector->text().toUInt());
+}
diff --git a/examples/network/secureudpserver/nicselector.h b/examples/network/secureudpserver/nicselector.h
new file mode 100644
index 0000000000..7962a78318
--- /dev/null
+++ b/examples/network/secureudpserver/nicselector.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef NICSELECTOR_H
+#define NICSELECTOR_H
+
+#include <QDialog>
+#include <QHostAddress>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+
+namespace Ui {
+class NicSelector;
+}
+
+QT_END_NAMESPACE
+
+QT_USE_NAMESPACE
+
+class NicSelector : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit NicSelector(QWidget *parent = nullptr);
+ ~NicSelector();
+
+ QHostAddress selectedIp() const;
+ quint16 selectedPort() const;
+
+private:
+ Ui::NicSelector *ui = nullptr;
+ QVector<QHostAddress> availableAddresses;
+};
+
+#endif // NICSELECTOR_H
diff --git a/examples/network/secureudpserver/nicselector.ui b/examples/network/secureudpserver/nicselector.ui
new file mode 100644
index 0000000000..b0ba376b66
--- /dev/null
+++ b/examples/network/secureudpserver/nicselector.ui
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NicSelector</class>
+ <widget class="QDialog" name="NicSelector">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>373</width>
+ <height>213</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>IP and port</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetFixedSize</enum>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Listen on address:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="ipSelector">
+ <property name="minimumSize">
+ <size>
+ <width>250</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetFixedSize</enum>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Port:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="portSelector">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>NicSelector</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>NicSelector</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/network/secureudpserver/secureudpserver.pro b/examples/network/secureudpserver/secureudpserver.pro
new file mode 100644
index 0000000000..910655aae4
--- /dev/null
+++ b/examples/network/secureudpserver/secureudpserver.pro
@@ -0,0 +1,21 @@
+QT += widgets network
+
+TARGET = secureudpserver
+TEMPLATE = app
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp \
+ server.cpp \
+ nicselector.cpp
+
+HEADERS += \
+ mainwindow.h \
+ server.h \
+ nicselector.h
+
+FORMS = mainwindow.ui \
+ nicselector.ui
+
+target.path = $$[QT_INSTALL_EXAMPLES]/network/secureudpserver
+INSTALLS += target
diff --git a/examples/network/secureudpserver/server.cpp b/examples/network/secureudpserver/server.cpp
new file mode 100644
index 0000000000..0d83fa9b51
--- /dev/null
+++ b/examples/network/secureudpserver/server.cpp
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "server.h"
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+QString peer_info(const QHostAddress &address, quint16 port)
+{
+ const static QString info = QStringLiteral("(%1:%2)");
+ return info.arg(address.toString()).arg(port);
+}
+
+QString connection_info(QSharedPointer<QDtls> connection)
+{
+ QString info(DtlsServer::tr("Session cipher: "));
+ info += connection->sessionCipher().name();
+
+ info += DtlsServer::tr("; session protocol: ");
+ switch (connection->sessionProtocol()) {
+ case QSsl::DtlsV1_0:
+ info += DtlsServer::tr("DTLS 1.0.");
+ break;
+ case QSsl::DtlsV1_2:
+ info += DtlsServer::tr("DTLS 1.2.");
+ break;
+ case QSsl::DtlsV1_2OrLater:
+ info += DtlsServer::tr("DTLS 1.2 or later.");
+ break;
+ default:
+ info += DtlsServer::tr("Unknown protocol.");
+ }
+
+ return info;
+}
+
+} // unnamed namespace
+
+//! [1]
+DtlsServer::DtlsServer()
+{
+ connect(&serverSocket, &QAbstractSocket::readyRead, this, &DtlsServer::readyRead);
+
+ serverConfiguration = QSslConfiguration::defaultDtlsConfiguration();
+ serverConfiguration.setPreSharedKeyIdentityHint("Qt DTLS example server");
+ serverConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
+}
+//! [1]
+
+DtlsServer::~DtlsServer()
+{
+ shutdown();
+}
+
+//! [2]
+bool DtlsServer::listen(const QHostAddress &address, quint16 port)
+{
+ if (address != serverSocket.localAddress() || port != serverSocket.localPort()) {
+ shutdown();
+ listening = serverSocket.bind(address, port);
+ if (!listening)
+ emit errorMessage(serverSocket.errorString());
+ } else {
+ listening = true;
+ }
+
+ return listening;
+}
+//! [2]
+
+bool DtlsServer::isListening() const
+{
+ return listening;
+}
+
+void DtlsServer::close()
+{
+ listening = false;
+}
+
+void DtlsServer::readyRead()
+{
+ //! [3]
+ const qint64 bytesToRead = serverSocket.pendingDatagramSize();
+ if (bytesToRead <= 0) {
+ emit warningMessage(tr("A spurious read notification"));
+ return;
+ }
+
+ QByteArray dgram(bytesToRead, Qt::Uninitialized);
+ QHostAddress peerAddress;
+ quint16 peerPort = 0;
+ const qint64 bytesRead = serverSocket.readDatagram(dgram.data(), dgram.size(),
+ &peerAddress, &peerPort);
+ if (bytesRead <= 0) {
+ emit warningMessage(tr("Failed to read a datagram: ") + serverSocket.errorString());
+ return;
+ }
+
+ dgram.resize(bytesRead);
+ //! [3]
+ //! [4]
+ if (peerAddress.isNull() || !peerPort) {
+ emit warningMessage(tr("Failed to extract peer info (address, port)"));
+ return;
+ }
+
+ const auto client = std::find_if(knownClients.begin(), knownClients.end(),
+ [&](const DtlsConnection &connection){
+ return connection->peerAddress() == peerAddress
+ && connection->peerPort() == peerPort;
+ });
+ //! [4]
+
+ //! [5]
+ if (client == knownClients.end())
+ return handleNewConnection(peerAddress, peerPort, dgram);
+ //! [5]
+
+ //! [6]
+ if ((*client)->isConnectionEncrypted()) {
+ decryptDatagram(*client, dgram);
+ if ((*client)->dtlsError() == QDtlsError::RemoteClosedConnectionError)
+ knownClients.erase(client);
+ return;
+ }
+ //! [6]
+
+ //! [7]
+ doHandshake(*client, dgram);
+ //! [7]
+}
+
+//! [13]
+void DtlsServer::pskRequired(QSslPreSharedKeyAuthenticator *auth)
+{
+ Q_ASSERT(auth);
+
+ emit infoMessage(tr("PSK callback, received a client's identity: '%1'")
+ .arg(QString::fromLatin1(auth->identity())));
+ auth->setPreSharedKey(QByteArrayLiteral("\x1a\x2b\x3c\x4d\x5e\x6f"));
+}
+//! [13]
+
+//! [8]
+void DtlsServer::handleNewConnection(const QHostAddress &peerAddress,
+ quint16 peerPort, const QByteArray &clientHello)
+{
+ if (!listening)
+ return;
+
+ const QString peerInfo = peer_info(peerAddress, peerPort);
+ if (cookieSender.verifyClient(&serverSocket, clientHello, peerAddress, peerPort)) {
+ emit infoMessage(peerInfo + tr(": verified, starting a handshake"));
+ //! [8]
+ //! [9]
+ DtlsConnection newConnection(new QDtls(QSslSocket::SslServerMode));
+ newConnection->setDtlsConfiguration(serverConfiguration);
+ newConnection->setPeer(peerAddress, peerPort);
+ newConnection->connect(newConnection.data(), &QDtls::pskRequired,
+ this, &DtlsServer::pskRequired);
+ knownClients.push_back(newConnection);
+ doHandshake(newConnection, clientHello);
+ //! [9]
+ } else if (cookieSender.dtlsError() != QDtlsError::NoError) {
+ emit errorMessage(tr("DTLS error: ") + cookieSender.dtlsErrorString());
+ } else {
+ emit infoMessage(peerInfo + tr(": not verified yet"));
+ }
+}
+
+//! [11]
+void DtlsServer::doHandshake(DtlsConnection newConnection, const QByteArray &clientHello)
+{
+ const bool result = newConnection->doHandshake(&serverSocket, clientHello);
+ if (!result) {
+ emit errorMessage(newConnection->dtlsErrorString());
+ return;
+ }
+
+ const QString peerInfo = peer_info(newConnection->peerAddress(),
+ newConnection->peerPort());
+ switch (newConnection->handshakeState()) {
+ case QDtls::HandshakeInProgress:
+ emit infoMessage(peerInfo + tr(": handshake is in progress ..."));
+ break;
+ case QDtls::HandshakeComplete:
+ emit infoMessage(tr("Connection with %1 encrypted. %2")
+ .arg(peerInfo, connection_info(newConnection)));
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+}
+//! [11]
+
+//! [12]
+void DtlsServer::decryptDatagram(DtlsConnection connection, const QByteArray &clientMessage)
+{
+ Q_ASSERT(connection->isConnectionEncrypted());
+
+ const QString peerInfo = peer_info(connection->peerAddress(), connection->peerPort());
+ const QByteArray dgram = connection->decryptDatagram(&serverSocket, clientMessage);
+ if (dgram.size()) {
+ emit datagramReceived(peerInfo, clientMessage, dgram);
+ connection->writeDatagramEncrypted(&serverSocket, tr("to %1: ACK").arg(peerInfo).toLatin1());
+ } else if (connection->dtlsError() == QDtlsError::NoError) {
+ emit warningMessage(peerInfo + ": " + tr("0 byte dgram, could be a re-connect attempt?"));
+ } else {
+ emit errorMessage(peerInfo + ": " + connection->dtlsErrorString());
+ }
+}
+//! [12]
+
+//! [14]
+void DtlsServer::shutdown()
+{
+ for (DtlsConnection &connection : knownClients)
+ connection->shutdown(&serverSocket);
+
+ knownClients.clear();
+ serverSocket.close();
+}
+//! [14]
+
+QT_END_NAMESPACE
diff --git a/examples/network/secureudpserver/server.h b/examples/network/secureudpserver/server.h
new file mode 100644
index 0000000000..b720368e7b
--- /dev/null
+++ b/examples/network/secureudpserver/server.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef SERVER_H
+#define SERVER_H
+
+#include <QtCore>
+#include <QtNetwork>
+
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+
+//! [0]
+class DtlsServer : public QObject
+{
+ Q_OBJECT
+
+public:
+ DtlsServer();
+ ~DtlsServer();
+
+ bool listen(const QHostAddress &address, quint16 port);
+ bool isListening() const;
+ void close();
+
+signals:
+ void errorMessage(const QString &message);
+ void warningMessage(const QString &message);
+ void infoMessage(const QString &message);
+
+ void datagramReceived(const QString &peerInfo, const QByteArray &cipherText,
+ const QByteArray &plainText);
+
+private slots:
+ void readyRead();
+ void pskRequired(QSslPreSharedKeyAuthenticator *auth);
+
+private:
+ void handleNewConnection(const QHostAddress &peerAddress, quint16 peerPort,
+ const QByteArray &clientHello);
+
+ using DtlsConnection = QSharedPointer<QDtls>;
+ void doHandshake(DtlsConnection newConnection, const QByteArray &clientHello);
+ void decryptDatagram(DtlsConnection connection, const QByteArray &clientMessage);
+ void shutdown();
+
+ bool listening = false;
+ QUdpSocket serverSocket;
+
+ QSslConfiguration serverConfiguration;
+ QDtlsClientVerifier cookieSender;
+ QVector<DtlsConnection> knownClients;
+
+ Q_DISABLE_COPY(DtlsServer)
+};
+//! [0]
+
+QT_END_NAMESPACE
+
+#endif // SERVER_H