1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
|
// Copyright (C) 2018 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "association.h"
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()
{
if (socket.pendingDatagramSize() <= 0) {
emit warningMessage(tr("%1: spurious read notification?").arg(name));
return;
}
//! [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]
|