快速安全 CoAP 客户端范例
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "qmlcoapsecureclient.h"
#include <QCoapReply>
#include <QFile>
#include <QLoggingCategory>
#include <QMetaEnum>
#include <QUrl>
Q_LOGGING_CATEGORY(lcCoapClient, "qt.coap.client")
QmlCoapSecureClient::QmlCoapSecureClient(QObject *parent)
: QObject(parent)
, m_coapClient(nullptr)
, m_securityMode(QtCoap::SecurityMode::NoSecurity)
{
}
QmlCoapSecureClient::~QmlCoapSecureClient()
{
if (m_coapClient) {
delete m_coapClient;
m_coapClient = nullptr;
}
}
static QString errorMessage(QtCoap::Error errorCode)
{
const auto error = QMetaEnum::fromType<QtCoap::Error>().valueToKey(static_cast<int>(errorCode));
return QString("Request failed with error: %1\n").arg(error);
}
void QmlCoapSecureClient::setSecurityMode(QtCoap::SecurityMode mode)
{
// Create a new client, if the security mode has changed
if (m_coapClient && mode != m_securityMode) {
delete m_coapClient;
m_coapClient = nullptr;
}
if (!m_coapClient) {
m_coapClient = new QCoapClient(mode);
m_securityMode = mode;
connect(m_coapClient, &QCoapClient::finished, this,
[this](QCoapReply *reply) {
if (!reply)
emit finished("Something went wrong, received a null reply");
else if (reply->errorReceived() != QtCoap::Error::Ok)
emit finished(errorMessage(reply->errorReceived()));
else
emit finished(reply->message().payload());
});
connect(m_coapClient, &QCoapClient::error, this,
[this](QCoapReply *, QtCoap::Error errorCode) {
emit finished(errorMessage(errorCode));
});
}
}
void QmlCoapSecureClient::sendGetRequest(const QString &host, const QString &path, int port)
{
if (!m_coapClient)
return;
m_coapClient->setSecurityConfiguration(m_configuration);
QUrl url;
url.setHost(host);
url.setPath(path);
url.setPort(port);
m_coapClient->get(url);
}
void
QmlCoapSecureClient::setSecurityConfiguration(const QString &preSharedKey, const QString &identity)
{
QCoapSecurityConfiguration configuration;
configuration.setPreSharedKey(preSharedKey.toUtf8());
configuration.setPreSharedKeyIdentity(identity.toUtf8());
m_configuration = configuration;
}
void QmlCoapSecureClient::setSecurityConfiguration(const QString &localCertificatePath,
const QString &caCertificatePath,
const QString &privateKeyPath)
{
QCoapSecurityConfiguration configuration;
const auto localCerts =
QSslCertificate::fromPath(QUrl(localCertificatePath).toLocalFile(), QSsl::Pem,
QSslCertificate::PatternSyntax::FixedString);
if (localCerts.isEmpty())
qCWarning(lcCoapClient, "The specified local certificate file is not valid.");
else
configuration.setLocalCertificateChain(localCerts.toVector());
const auto caCerts = QSslCertificate::fromPath(QUrl(caCertificatePath).toLocalFile(), QSsl::Pem,
QSslCertificate::PatternSyntax::FixedString);
if (caCerts.isEmpty())
qCWarning(lcCoapClient, "The specified CA certificate file is not valid.");
else
configuration.setCaCertificates(caCerts.toVector());
QFile privateKey(QUrl(privateKeyPath).toLocalFile());
if (privateKey.open(QIODevice::ReadOnly)) {
QCoapPrivateKey key(privateKey.readAll(), QSsl::Ec);
configuration.setPrivateKey(key);
} else {
qCWarning(lcCoapClient) << "Unable to read the specified private key file"
<< privateKeyPath;
}
m_configuration = configuration;
}
void QmlCoapSecureClient::disconnect()
{
if (m_coapClient)
m_coapClient->disconnect();
}