diff options
| author | Øystein Heskestad <oystein.heskestad@qt.io> | 2023-05-22 16:41:35 +0200 |
|---|---|---|
| committer | Øystein Heskestad <oystein.heskestad@qt.io> | 2023-06-06 07:35:51 +0000 |
| commit | 743de69538696ea14e299c32056d40851bb9fdcd (patch) | |
| tree | bbe4b9197043614d8d13700afa383257ed75f081 /examples/remoteobjects | |
| parent | 98522adc399e4fcd97808a0ae4c3a231d6c67739 (diff) | |
Revamp SSL example
The example did not work because the two applications used different
rep-files to generate the remote objects. Use the same file in both
applications, fix usage of case in naming, expand the documentation,
and add a picture. Remove unused PresetData from rep-file.
Task-number: QTBUG-112850
Pick-to: 6.5 6.6
Change-Id: Ia7aafc52d647bca9ffec12b8dd548377f20b6ce4
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
Diffstat (limited to 'examples/remoteobjects')
| -rw-r--r-- | examples/remoteobjects/ssl/doc/src/ssl.qdoc | 69 | ||||
| -rw-r--r-- | examples/remoteobjects/ssl/sslcppclient/CMakeLists.txt | 33 | ||||
| -rw-r--r-- | examples/remoteobjects/ssl/sslcppclient/main.cpp | 33 | ||||
| -rw-r--r-- | examples/remoteobjects/ssl/sslcppclient/sslcppclient.pro | 7 | ||||
| -rw-r--r-- | examples/remoteobjects/ssl/sslcppclient/timemodel.rep | 12 | ||||
| -rw-r--r-- | examples/remoteobjects/ssl/sslserver/CMakeLists.txt | 23 | ||||
| -rw-r--r-- | examples/remoteobjects/ssl/sslserver/main.cpp | 52 | ||||
| -rw-r--r-- | examples/remoteobjects/ssl/sslserver/sslserver.cpp | 32 | ||||
| -rw-r--r-- | examples/remoteobjects/ssl/sslserver/sslserver.h | 24 | ||||
| -rw-r--r-- | examples/remoteobjects/ssl/sslserver/sslserver.pro | 6 | ||||
| -rw-r--r-- | examples/remoteobjects/timemodel.rep | 1 |
11 files changed, 150 insertions, 142 deletions
diff --git a/examples/remoteobjects/ssl/doc/src/ssl.qdoc b/examples/remoteobjects/ssl/doc/src/ssl.qdoc index 90b6725..3ceeece 100644 --- a/examples/remoteobjects/ssl/doc/src/ssl.qdoc +++ b/examples/remoteobjects/ssl/doc/src/ssl.qdoc @@ -3,10 +3,75 @@ /*! \example ssl - \title QtRemoteObjects SSL Example + \title SSL Server and Client \brief Setting up a secure Remote Object network using QSslSockets. + \examplecategory {Input/Output} + \meta tag {rpc,network,tls} \ingroup qtremoteobjects-examples Encrypting communication is critical when you need to pass data - through a network you don't have full control over. + through a network you don't have full control over. The two applications + in this example show how to share remote objects over an SSL connection, + and how to access them. + + \image ssl-example.webp + + Both \e sslserver and \e sslcppclient use a custom root CA certificate to + validate each other's certificates all located in sslserver/cert. + + \section1 SSL Server + + The \e sslserver is configured with certificates and a private key. + + \snippet ssl/sslserver/main.cpp 0 + + Then it creates a QRemoteObjectHost object and a QSslServer object. + The QSslServer object listens on port 65511. Then setHostUrl is called + on the QRemoteObjectHost object with the URL of the QSslServer object. + + \snippet ssl/sslserver/main.cpp 1 + + A lambda is used to handle the errorOccurred signal by outputting the + error to the terminal. A second lambda is connected to the + pendingConnectionAvailable signal, which connects an error handler, + and calls addHostSideConnection on the QRemoteObjectHost object with + the incoming socket as argument to make the host object use the socket + for communication. + + \snippet ssl/sslserver/main.cpp 2 + + Finally, a MinuteTimer object is created and enableRemoting is called on + the QRemoteObjectHost object with the MinuteTimer object as argument to + enable it to be shared. + + \snippet ssl/sslserver/main.cpp 3 + + \section1 SSL Client + + The \e sslcppclient sets the root CA certificate and then creates a + Tester object. + + \snippet ssl/sslcppclient/main.cpp 3 + + In the Tester constructor a temporary QRemoteObjectNode object is + created, and setupConnection is used to create and configure a + QSslSocket object. An error handler is connected, and the QSslSocket is + used by the QRemoteObjectNode object by calling addClientSideConnection + on it. + + \snippet ssl/sslcppclient/main.cpp 0 + + Then three QScopedPointer that are members of the Tester class are + connected to three replicas of MinuteTimer by using acquire on the + QRemoteObjectNode object. Finally QTimer::singleShot is used four times + to call reset after a delay. + + \snippet ssl/sslcppclient/main.cpp 1 + + When Tester::clear is called for the first three times, one pointer is + checked that it is bound and then reset, for a different pointer each + time. When it is called for the fourth time it causes the application + to quit. + + \snippet ssl/sslcppclient/main.cpp 2 */ diff --git a/examples/remoteobjects/ssl/sslcppclient/CMakeLists.txt b/examples/remoteobjects/ssl/sslcppclient/CMakeLists.txt index db39fd6..d46747d 100644 --- a/examples/remoteobjects/ssl/sslcppclient/CMakeLists.txt +++ b/examples/remoteobjects/ssl/sslcppclient/CMakeLists.txt @@ -2,33 +2,26 @@ # SPDX-License-Identifier: BSD-3-Clause cmake_minimum_required(VERSION 3.16) -project(SslCppClient LANGUAGES CXX) +project(sslcppclient LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_AUTOMOC ON) - -if(NOT DEFINED INSTALL_EXAMPLESDIR) - set(INSTALL_EXAMPLESDIR "examples") -endif() - -set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/ssl/sslcppclient") find_package(Qt6 REQUIRED COMPONENTS Core RemoteObjects) -qt_add_executable(SslCppClient +qt_standard_project_setup() + +qt_add_executable(sslcppclient main.cpp ) -set_target_properties(SslCppClient PROPERTIES +set_target_properties(sslcppclient PROPERTIES WIN32_EXECUTABLE TRUE MACOSX_BUNDLE FALSE ) -target_link_libraries(SslCppClient PUBLIC - # Remove: gui +target_link_libraries(sslcppclient PRIVATE Qt::Core Qt::RemoteObjects - Qt::RemoteObjectsPrivate ) # Resources: @@ -38,11 +31,9 @@ set(cert_resource_files "../sslserver/cert/rootCA.key" "../sslserver/cert/rootCA.pem" "../sslserver/cert/rootCA.srl" - "../sslserver/cert/server.crt" - "../sslserver/cert/server.key" ) -qt6_add_resources(SslCppClient "cert" +qt6_add_resources(sslcppclient "cert" PREFIX "/sslcert" BASE @@ -51,12 +42,6 @@ qt6_add_resources(SslCppClient "cert" ${cert_resource_files} ) -qt6_add_repc_replicas(SslCppClient - timemodel.rep -) - -install(TARGETS SslCppClient - RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" - BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" - LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +qt6_add_repc_replicas(sslcppclient + ../../timemodel.rep ) diff --git a/examples/remoteobjects/ssl/sslcppclient/main.cpp b/examples/remoteobjects/ssl/sslcppclient/main.cpp index 9d49a12..33a3437 100644 --- a/examples/remoteobjects/ssl/sslcppclient/main.cpp +++ b/examples/remoteobjects/ssl/sslcppclient/main.cpp @@ -11,12 +11,13 @@ #include <QRemoteObjectNode> -class tester : public QObject +class Tester : public QObject { Q_OBJECT public: - tester() : QObject(nullptr) + Tester() : QObject(nullptr) { + //! [0] QRemoteObjectNode m_client; auto socket = setupConnection(); connect(socket, &QSslSocket::errorOccurred, @@ -24,35 +25,49 @@ public: qDebug() << "QSslSocket::error" << error; }) ; m_client.addClientSideConnection(socket); + //! [0] + //! [1] ptr1.reset(m_client.acquire< MinuteTimerReplica >()); ptr2.reset(m_client.acquire< MinuteTimerReplica >()); ptr3.reset(m_client.acquire< MinuteTimerReplica >()); - QTimer::singleShot(0, this, &tester::clear); - QTimer::singleShot(1, this, &tester::clear); - QTimer::singleShot(10000, this, &tester::clear); - QTimer::singleShot(11000, this, &tester::clear); + QTimer::singleShot(0, this, &Tester::clear); + QTimer::singleShot(1, this, &Tester::clear); + QTimer::singleShot(10000, this, &Tester::clear); + QTimer::singleShot(11000, this, &Tester::clear); + //! [1] } public slots: + + //! [2] void clear() { static int i = 0; if (i == 0) { i++; + if (ptr1.isNull()) + qCritical() << "Pointer 1 was not set"; ptr1.reset(); } else if (i == 1) { i++; + if (ptr2.isNull()) + qCritical() << "Pointer 2 was not set"; ptr2.reset(); } else if (i == 2) { i++; + if (ptr3.isNull()) + qCritical() << "Pointer 3 was not set"; ptr3.reset(); } else { qApp->quit(); } } + //! [2] private: - QScopedPointer<MinuteTimerReplica> ptr1, ptr2, ptr3; + QScopedPointer<MinuteTimerReplica> ptr1; + QScopedPointer<MinuteTimerReplica> ptr2; + QScopedPointer<MinuteTimerReplica> ptr3; QSslSocket *setupConnection() { @@ -70,6 +85,7 @@ private: } }; +//! [3] int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); @@ -78,8 +94,9 @@ int main(int argc, char *argv[]) config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem"))); QSslConfiguration::setDefaultConfiguration(config); - tester t; + Tester t; return a.exec(); } +//! [3] #include "main.moc" diff --git a/examples/remoteobjects/ssl/sslcppclient/sslcppclient.pro b/examples/remoteobjects/ssl/sslcppclient/sslcppclient.pro index 07fb8da..c616441 100644 --- a/examples/remoteobjects/ssl/sslcppclient/sslcppclient.pro +++ b/examples/remoteobjects/ssl/sslcppclient/sslcppclient.pro @@ -1,21 +1,18 @@ QT_FOR_CONFIG += network requires(qtConfig(ssl)) -REPC_REPLICA += timemodel.rep +REPC_REPLICA += ../../timemodel.rep QT = remoteobjects remoteobjects-private core QT -= gui -TARGET = SslCppClient +TARGET = sslcppclient CONFIG -= app_bundle TEMPLATE = app SOURCES += main.cpp -OTHER_FILES += \ - timemodel.rep - RESOURCES += \ ../sslserver/cert/cert.qrc diff --git a/examples/remoteobjects/ssl/sslcppclient/timemodel.rep b/examples/remoteobjects/ssl/sslcppclient/timemodel.rep deleted file mode 100644 index cbfaf24..0000000 --- a/examples/remoteobjects/ssl/sslcppclient/timemodel.rep +++ /dev/null @@ -1,12 +0,0 @@ -#include <QtCore> - -POD PresetInfo(int presetNumber, float frequency, QString stationName) -class MinuteTimer -{ - PROP(int hour=1); - PROP(int minute=51); - SIGNAL(timeChanged()); - SIGNAL(timeChanged2(QTime t)); - SIGNAL(sendCustom(PresetInfo info)); - SLOT(void SetTimeZone(int zn)); -}; diff --git a/examples/remoteobjects/ssl/sslserver/CMakeLists.txt b/examples/remoteobjects/ssl/sslserver/CMakeLists.txt index 4296a12..18bb7bb 100644 --- a/examples/remoteobjects/ssl/sslserver/CMakeLists.txt +++ b/examples/remoteobjects/ssl/sslserver/CMakeLists.txt @@ -5,37 +5,28 @@ cmake_minimum_required(VERSION 3.16) project(sslserver LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(CMAKE_AUTOMOC ON) - -if(NOT DEFINED INSTALL_EXAMPLESDIR) - set(INSTALL_EXAMPLESDIR "examples") -endif() - -set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/remoteobjects/ssl/sslserver") find_package(Qt6 REQUIRED COMPONENTS Core RemoteObjects) +qt_standard_project_setup() + qt_add_executable(sslserver main.cpp - sslserver.cpp sslserver.h timemodel.cpp timemodel.h ) set_target_properties(sslserver PROPERTIES WIN32_EXECUTABLE FALSE - MACOSX_BUNDLE TRUE + MACOSX_BUNDLE FALSE ) -target_link_libraries(sslserver PUBLIC +target_link_libraries(sslserver PRIVATE Qt::Core Qt::RemoteObjects - Qt::RemoteObjectsPrivate ) # Resources: set(cert_resource_files - "cert/client.crt" - "cert/client.key" "cert/rootCA.key" "cert/rootCA.pem" "cert/rootCA.srl" @@ -55,9 +46,3 @@ qt6_add_resources(sslserver "cert" qt6_add_repc_sources(sslserver ../../timemodel.rep ) - -install(TARGETS sslserver - RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" - BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" - LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" -) diff --git a/examples/remoteobjects/ssl/sslserver/main.cpp b/examples/remoteobjects/ssl/sslserver/main.cpp index d882d9c..8c7b593 100644 --- a/examples/remoteobjects/ssl/sslserver/main.cpp +++ b/examples/remoteobjects/ssl/sslserver/main.cpp @@ -5,8 +5,8 @@ #include <QCoreApplication> #include <QSslConfiguration> - -#include "sslserver.h" +#include <QSslKey> +#include <QSslServer> #include <QRemoteObjectHost> /* @@ -37,9 +37,9 @@ BOOL WINAPI WinHandler(DWORD CEvent) { case CTRL_C_EVENT: SigIntHandler(); - break; + return TRUE; } - return TRUE; + return FALSE; } #endif @@ -47,31 +47,61 @@ int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); + //! [0] auto config = QSslConfiguration::defaultConfiguration(); config.setCaCertificates(QSslCertificate::fromPath(QStringLiteral(":/sslcert/rootCA.pem"))); + QFile certificateFile(QStringLiteral(":/sslcert/server.crt")); + if (certificateFile.open(QIODevice::ReadOnly | QIODevice::Text)) + config.setLocalCertificate(QSslCertificate(certificateFile.readAll(), QSsl::Pem)); + else + qFatal("Could not open certificate file"); + QFile keyFile(QStringLiteral(":/sslcert/server.key")); + if (keyFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + QSslKey key(keyFile.readAll(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey); + if (key.isNull()) + qFatal("Key is not valid"); + config.setPrivateKey(key); + } else { + qFatal("Could not open key file"); + } + config.setPeerVerifyMode(QSslSocket::VerifyPeer); QSslConfiguration::setDefaultConfiguration(config); + //! [0] #if defined(Q_OS_UNIX) || defined(Q_OS_LINUX) || defined(Q_OS_QNX) signal(SIGINT, &unix_handler); #elif defined(Q_OS_WIN32) SetConsoleCtrlHandler((PHANDLER_ROUTINE)WinHandler, TRUE); #endif + //! [1] QRemoteObjectHost host; - SslServer server; + QSslServer server; server.listen(QHostAddress::Any, 65511); - host.setHostUrl(server.serverAddress().toString(), QRemoteObjectHost::AllowExternalRegistration); - - QObject::connect(&server, &SslServer::encryptedSocketReady, &server, [&host](QSslSocket *socket) { + //! [1] + + //! [2] + QObject::connect(&server, &QSslServer::errorOccurred, + [](QSslSocket *socket, QAbstractSocket::SocketError error) { + Q_UNUSED(socket); + qDebug() << "QSslServer::errorOccurred" << error; + }); + QObject::connect(&server, &QSslServer::pendingConnectionAvailable, [&server, &host]() { + qDebug() << "New connection available"; + QSslSocket *socket = qobject_cast<QSslSocket *>(server.nextPendingConnection()); + Q_ASSERT(socket); QObject::connect(socket, &QSslSocket::errorOccurred, - socket, [](QAbstractSocket::SocketError error){ - qDebug() << "QSslSocket::error" << error; - }) ; + [](QAbstractSocket::SocketError error) { + qDebug() << "QSslSocket::error" << error; + }); host.addHostSideConnection(socket); }); + //! [2] + //! [3] MinuteTimer timer; host.enableRemoting(&timer); + //! [3] Q_UNUSED(timer) return app.exec(); diff --git a/examples/remoteobjects/ssl/sslserver/sslserver.cpp b/examples/remoteobjects/ssl/sslserver/sslserver.cpp deleted file mode 100644 index 98c0402..0000000 --- a/examples/remoteobjects/ssl/sslserver/sslserver.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2018 Ford Motor Company -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include "sslserver.h" -#include <QSslSocket> - -SslServer::SslServer(QObject *parent) - : QTcpServer(parent) -{} - - -void SslServer::incomingConnection(qintptr socketDescriptor) -{ - auto serverSocket = new QSslSocket; - if (serverSocket->setSocketDescriptor(socketDescriptor)) { - addPendingConnection(serverSocket); - connect(serverSocket, &QSslSocket::encrypted, this, [this, serverSocket] { - Q_EMIT encryptedSocketReady(serverSocket); - }); - connect(serverSocket, static_cast<void (QSslSocket::*)(const QList<QSslError>&)>(&QSslSocket::sslErrors), - this, [serverSocket](const QList<QSslError>& errors){ - qWarning() << "Error:" << serverSocket << errors; - delete serverSocket; - }); - serverSocket->setPeerVerifyMode(QSslSocket::VerifyPeer); - serverSocket->setLocalCertificate(QStringLiteral(":/sslcert/server.crt")); - serverSocket->setPrivateKey(QStringLiteral(":/sslcert/server.key")); - serverSocket->startServerEncryption(); - } else { - delete serverSocket; - } -} diff --git a/examples/remoteobjects/ssl/sslserver/sslserver.h b/examples/remoteobjects/ssl/sslserver/sslserver.h deleted file mode 100644 index c3ffbca..0000000 --- a/examples/remoteobjects/ssl/sslserver/sslserver.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2018 Ford Motor Company -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#ifndef SSLSERVER_H -#define SSLSERVER_H - -#include <QTcpServer> - -QT_BEGIN_NAMESPACE -class QSslSocket; -QT_END_NAMESPACE - -class SslServer : public QTcpServer -{ - Q_OBJECT -public: - SslServer(QObject *parent=nullptr); - void incomingConnection(qintptr socketDescriptor) override; - -signals: - void encryptedSocketReady(QSslSocket *socket); -}; - -#endif // SSLSERVER_H diff --git a/examples/remoteobjects/ssl/sslserver/sslserver.pro b/examples/remoteobjects/ssl/sslserver/sslserver.pro index b8081d2..7e93815 100644 --- a/examples/remoteobjects/ssl/sslserver/sslserver.pro +++ b/examples/remoteobjects/ssl/sslserver/sslserver.pro @@ -7,10 +7,8 @@ CONFIG += console REPC_SOURCE += ../../timemodel.rep QT = remoteobjects remoteobjects-private core -SOURCES += timemodel.cpp main.cpp \ - sslserver.cpp -HEADERS += timemodel.h \ - sslserver.h +SOURCES += timemodel.cpp main.cpp +HEADERS += timemodel.h contains(QT_CONFIG, c++11): CONFIG += c++11 diff --git a/examples/remoteobjects/timemodel.rep b/examples/remoteobjects/timemodel.rep index c07ee2c..045be06 100644 --- a/examples/remoteobjects/timemodel.rep +++ b/examples/remoteobjects/timemodel.rep @@ -1,7 +1,6 @@ #include <QtCore> POD PresetInfo(int presetNumber, float frequency, QString stationName) -POD PresetData(QList<QString> bla) class MinuteTimer { PROP(int hour=1); |
