diff options
author | Karsten Heimrich <karsten.heimrich@qt.io> | 2019-03-28 16:29:41 +0100 |
---|---|---|
committer | Karsten Heimrich <karsten.heimrich@qt.io> | 2019-03-29 11:55:02 +0000 |
commit | 272249ce5bd5cd08082f2a00944fa92ef12c3076 (patch) | |
tree | 9132d88919ef8b35c9121bb48f69d37d62da53b9 | |
parent | 2e67dd4c5eb463bd71fe8c382b45fc3c0eb47403 (diff) |
Implement secure session support in the KNX editor example
Change-Id: I614acc69226f0c747c8acb1103e87f81f304f02a
Reviewed-by: Karsten Heimrich <karsten.heimrich@qt.io>
-rw-r--r-- | examples/knx/knxeditor/localdevicemanagement.cpp | 43 | ||||
-rw-r--r-- | examples/knx/knxeditor/localdevicemanagement.h | 5 | ||||
-rw-r--r-- | examples/knx/knxeditor/localdevicemanagement.ui | 61 | ||||
-rw-r--r-- | examples/knx/knxeditor/mainwindow.cpp | 31 | ||||
-rw-r--r-- | examples/knx/knxeditor/mainwindow.h | 4 | ||||
-rw-r--r-- | examples/knx/knxeditor/mainwindow.ui | 13 | ||||
-rw-r--r-- | examples/knx/knxeditor/tunneling.cpp | 52 | ||||
-rw-r--r-- | examples/knx/knxeditor/tunneling.h | 8 | ||||
-rw-r--r-- | examples/knx/knxeditor/tunneling.ui | 177 | ||||
-rw-r--r-- | examples/knx/knxeditor/tunnelingfeatures.cpp | 64 | ||||
-rw-r--r-- | examples/knx/knxeditor/tunnelingfeatures.h | 7 | ||||
-rw-r--r-- | examples/knx/knxeditor/tunnelingfeatures.ui | 125 |
12 files changed, 442 insertions, 148 deletions
diff --git a/examples/knx/knxeditor/localdevicemanagement.cpp b/examples/knx/knxeditor/localdevicemanagement.cpp index 46504fd..dd52493 100644 --- a/examples/knx/knxeditor/localdevicemanagement.cpp +++ b/examples/knx/knxeditor/localdevicemanagement.cpp @@ -52,8 +52,9 @@ #include "ui_localdevicemanagement.h" #include <QKnxByteArray> -#include <QtKnx/QKnxDeviceManagementFrameBuilder> +#include <QKnxDeviceManagementFrameBuilder> #include <QKnxInterfaceObjectPropertyDataType> +#include <QKnxNetIpSecureConfiguration> #include <QMetaEnum> #include <QMetaType> #include <QTreeWidget> @@ -82,9 +83,16 @@ LocalDeviceManagement::LocalDeviceManagement(QWidget* parent) connect(ui->connectRequestDeviceManagement, &QPushButton::clicked, this, [&]() { m_management.setLocalPort(0); - m_management.connectToHost(m_server.controlEndpointAddress(), - m_server.controlEndpointPort(), - m_proto); + if (ui->secureSessionCheckBox->isChecked()) { + auto config = m_configs.value(ui->secureSessionCb->currentIndex()); + config.setKeepSecureSessionAlive(true); + m_management.setSecureConfiguration(config); + m_management.connectToHostEncrypted(m_server.controlEndpointAddress(), + m_server.controlEndpointPort()); + } else { + m_management.connectToHost(m_server.controlEndpointAddress(), + m_server.controlEndpointPort(), m_proto); + } }); connect(&m_management, &QKnxNetIpDeviceManagement::connected, this, [&] { @@ -139,7 +147,7 @@ LocalDeviceManagement::LocalDeviceManagement(QWidget* parent) connect(&m_management, &QKnxNetIpDeviceManagement::errorOccurred, this, [&] (QKnxNetIpEndpointConnection::Error, QString errorString) { - ui->textOuputDeviceManagement->append(errorString); + ui->textOuputDeviceManagement->append(errorString); }); ui->cemiData->setValidator(new QRegExpValidator(QRegExp("[0-9a-fA-F]+"))); @@ -172,6 +180,8 @@ void LocalDeviceManagement::setKnxNetIpServer(const QKnxNetIpServerInfo &server) ui->connectRequestDeviceManagement->setEnabled(true); ui->disconnectRequestDeviceManagement->setEnabled(false); } + + updateSecureConfigCombo(); ui->deviceManagementSendRequest->setEnabled(false); } @@ -281,6 +291,12 @@ void LocalDeviceManagement::on_manualInput_clicked(bool checked) } } +void LocalDeviceManagement::onKeyringChanged(const QVector<QKnxNetIpSecureConfiguration> &configs) +{ + m_configs = configs; + updateSecureConfigCombo(); +} + void LocalDeviceManagement::setupMessageCodeComboBox() { ui->mc->addItem("M_PropRead.req", @@ -411,3 +427,20 @@ void LocalDeviceManagement::selectFirstSubitem(QTreeWidget *treeWidget, QTreeWid treeWidget->setCurrentItem(treeWidget->invisibleRootItem(), 0); comboBox->setRootModelIndex(treeWidget->currentIndex()); } + +void LocalDeviceManagement::updateSecureConfigCombo() +{ + ui->secureSessionCb->clear(); + + ui->secureSessionCheckBox->setEnabled(!m_configs.isEmpty()); + ui->secureSessionCheckBox->setChecked(m_proto == QKnxNetIp::HostProtocol::TCP_IPv4); + + for (int i = 0; i < m_configs.size(); ++i) { + const auto &config = m_configs[i]; + if (m_server.individualAddress() != config.host()) + continue; + + ui->secureSessionCb->addItem(tr("User ID: %1 (Individual Address: %2)").arg(config.userId()) + .arg(config.individualAddress().toString()), i); + } +} diff --git a/examples/knx/knxeditor/localdevicemanagement.h b/examples/knx/knxeditor/localdevicemanagement.h index 218ad95..195023f 100644 --- a/examples/knx/knxeditor/localdevicemanagement.h +++ b/examples/knx/knxeditor/localdevicemanagement.h @@ -51,9 +51,9 @@ #ifndef LOCALDEVICEMANAGEMENT_H #define LOCALDEVICEMANAGEMENT_H -#include <QWidget> #include <QKnxNetIpDeviceManagement> #include <QKnxNetIpServerInfo> +#include <QWidget> QT_BEGIN_NAMESPACE namespace Ui { @@ -78,6 +78,7 @@ public: void setLocalAddress(const QHostAddress &address); void setKnxNetIpServer(const QKnxNetIpServerInfo &server); void setTcpEnable(bool value); + void onKeyringChanged(const QVector<QKnxNetIpSecureConfiguration> &configs); public slots: void clearLogging(); @@ -100,6 +101,7 @@ private: int keyToValue(const QMetaObject &object, const QString &key, bool *ok); void setupComboBox(QComboBox *comboBox, const QMetaObject &object, const QSet<int> &values = {}); void selectFirstSubitem(QTreeWidget *treeView, QTreeWidgetItem *rootItem, QComboBox *comboBox); + void updateSecureConfigCombo(); private: Ui::LocalDeviceManagement *ui { nullptr }; @@ -110,6 +112,7 @@ private: QKnxNetIpServerInfo m_server; QKnxNetIpDeviceManagement m_management; QKnxNetIp::HostProtocol m_proto { QKnxNetIp::HostProtocol::UDP_IPv4 }; + QVector<QKnxNetIpSecureConfiguration> m_configs; }; #endif diff --git a/examples/knx/knxeditor/localdevicemanagement.ui b/examples/knx/knxeditor/localdevicemanagement.ui index 05c3145..99d809f 100644 --- a/examples/knx/knxeditor/localdevicemanagement.ui +++ b/examples/knx/knxeditor/localdevicemanagement.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>830</width> + <width>856</width> <height>385</height> </rect> </property> @@ -265,6 +265,29 @@ <item> <layout class="QHBoxLayout" name="horizontalLayout_3"> <item> + <widget class="QCheckBox" name="secureSessionCheckBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Use secure session</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="secureSessionCb"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> @@ -387,8 +410,8 @@ <y>45</y> </hint> <hint type="destinationlabel"> - <x>332</x> - <y>16</y> + <x>384</x> + <y>26</y> </hint> </hints> </connection> @@ -403,8 +426,8 @@ <y>42</y> </hint> <hint type="destinationlabel"> - <x>439</x> - <y>22</y> + <x>485</x> + <y>29</y> </hint> </hints> </connection> @@ -419,8 +442,8 @@ <y>49</y> </hint> <hint type="destinationlabel"> - <x>753</x> - <y>19</y> + <x>845</x> + <y>29</y> </hint> </hints> </connection> @@ -451,8 +474,8 @@ <y>49</y> </hint> <hint type="destinationlabel"> - <x>666</x> - <y>19</y> + <x>752</x> + <y>29</y> </hint> </hints> </connection> @@ -467,8 +490,24 @@ <y>49</y> </hint> <hint type="destinationlabel"> - <x>378</x> - <y>19</y> + <x>433</x> + <y>29</y> + </hint> + </hints> + </connection> + <connection> + <sender>secureSessionCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>secureSessionCb</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>16</x> + <y>368</y> + </hint> + <hint type="destinationlabel"> + <x>147</x> + <y>369</y> </hint> </hints> </connection> diff --git a/examples/knx/knxeditor/mainwindow.cpp b/examples/knx/knxeditor/mainwindow.cpp index 17200ef..a06abd5 100644 --- a/examples/knx/knxeditor/mainwindow.cpp +++ b/examples/knx/knxeditor/mainwindow.cpp @@ -52,8 +52,11 @@ #include "ui_mainwindow.h" #include <QElapsedTimer> +#include <QFileDialog> +#include <QInputDialog> #include <QNetworkInterface> #include <QStandardItem> +#include <QStandardPaths> Ui::MainWindow *MainWindow::s_ui { nullptr }; @@ -274,6 +277,34 @@ void MainWindow::on_radioButtonTCP_toggled(bool checked) ui->tunnelingFeatures->setTcpEnable(checked); } +void MainWindow::on_actionEtsKeyringImport_triggered() +{ + auto fileName = QFileDialog::getOpenFileName(this, tr("Import keyring file"), + QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).value(0), + tr("KNX keyring file (*.knxkeys)")); + + if (fileName.isEmpty()) + return; + + bool ok; + auto password = QInputDialog::getText(this, tr("Import keyring file"), + tr("Keyring file password:"), QLineEdit::Normal, {}, &ok); + if (!ok || password.isEmpty()) + return; + + auto mgmtConfigs = QKnxNetIpSecureConfiguration::fromKeyring(QKnxNetIpSecureConfiguration + ::Type::DeviceManagement, fileName, password.toUtf8(), true); + ui->deviceManagement->onKeyringChanged(mgmtConfigs); + + for (auto &config : mgmtConfigs) + config.setIndividualAddress({}); + + auto tunnelConfigs = QKnxNetIpSecureConfiguration::fromKeyring(QKnxNetIpSecureConfiguration + ::Type::Tunneling, fileName, password.toUtf8(), true); + ui->tunneling->onKeyringChanged(mgmtConfigs + tunnelConfigs); + ui->tunnelingFeatures->onKeyringChanged(mgmtConfigs + tunnelConfigs); +} + void MainWindow::fillLocalIpBox() { auto firstItem = new QStandardItem(tr("Interface: IP address --Select One--")); diff --git a/examples/knx/knxeditor/mainwindow.h b/examples/knx/knxeditor/mainwindow.h index 8aa256f..6c1a3d7 100644 --- a/examples/knx/knxeditor/mainwindow.h +++ b/examples/knx/knxeditor/mainwindow.h @@ -69,11 +69,15 @@ public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); +signals: + void keyringChanged(const QString &fileName, const QString &password); + private slots: void newServerSelected(int serverBoxIndex); void newIPAddressSelected(int localIpBoxIndex); void showServerAndServices(const QKnxNetIpServerInfo &info); void on_radioButtonTCP_toggled(bool checked); + void on_actionEtsKeyringImport_triggered(); private: void fillLocalIpBox(); diff --git a/examples/knx/knxeditor/mainwindow.ui b/examples/knx/knxeditor/mainwindow.ui index 0682a17..65ff6a3 100644 --- a/examples/knx/knxeditor/mainwindow.ui +++ b/examples/knx/knxeditor/mainwindow.ui @@ -247,7 +247,13 @@ <property name="title"> <string>File</string> </property> - <addaction name="separator"/> + <widget class="QMenu" name="menuImport"> + <property name="title"> + <string>Import</string> + </property> + <addaction name="actionEtsKeyringImport"/> + </widget> + <addaction name="menuImport"/> <addaction name="separator"/> <addaction name="actionExit"/> </widget> @@ -310,6 +316,11 @@ <string>Clear All</string> </property> </action> + <action name="actionEtsKeyringImport"> + <property name="text"> + <string>KNX keyring file...</string> + </property> + </action> </widget> <customwidgets> <customwidget> diff --git a/examples/knx/knxeditor/tunneling.cpp b/examples/knx/knxeditor/tunneling.cpp index 6f2cd56..6a5e967 100644 --- a/examples/knx/knxeditor/tunneling.cpp +++ b/examples/knx/knxeditor/tunneling.cpp @@ -51,11 +51,13 @@ #include "tunneling.h" #include "ui_tunneling.h" -#include <QtCore/QMetaEnum> -#include <QtCore/QMetaType> -#include <QtGui/QStandardItemModel> -#include <QtKnx/QKnxLinkLayerFrameBuilder> -#include <QtWidgets/QTreeView> +#include <QKnxLinkLayerFrameBuilder> +#include <QKnxNetIpSecureConfiguration> +#include <QMetaEnum> +#include <QMetaType> +#include <QStandardItemModel> +#include <QTreeView> +#include <QTreeWidget> // -- KnxAddressValidator @@ -94,9 +96,16 @@ Tunneling::Tunneling(QWidget* parent) connect(ui->connectTunneling, &QPushButton::clicked, this, [&]() { m_tunnel.setLocalPort(0); - m_tunnel.connectToHost(m_server.controlEndpointAddress(), - m_server.controlEndpointPort(), - m_proto); + if (ui->secureSessionCheckBox->isChecked()) { + auto config = m_configs.value(ui->secureSessionCb->currentIndex()); + config.setKeepSecureSessionAlive(true); + m_tunnel.setSecureConfiguration(config); + m_tunnel.connectToHostEncrypted(m_server.controlEndpointAddress(), + m_server.controlEndpointPort()); + } else { + m_tunnel.connectToHost(m_server.controlEndpointAddress(), + m_server.controlEndpointPort(), m_proto); + } }); connect(&m_tunnel, &QKnxNetIpTunnel::connected, this, [&] { @@ -266,6 +275,8 @@ void Tunneling::setKnxNetIpServer(const QKnxNetIpServerInfo &server) ui->connectTunneling->setEnabled(true); ui->disconnectTunneling->setEnabled(false); } + + updateSecureConfigCombo(); ui->tunnelingSendRequest->setEnabled(false); } @@ -334,6 +345,12 @@ void Tunneling::on_manualInput_clicked(bool checked) ui->cemiFrame->setFocus(); } +void Tunneling::onKeyringChanged(const QVector<QKnxNetIpSecureConfiguration> &configs) +{ + m_configs = configs; + updateSecureConfigCombo(); +} + void Tunneling::setupApciTpciComboBox() { int index = QKnxTpdu::staticMetaObject.indexOfEnumerator("ApplicationControlField"); @@ -387,3 +404,22 @@ void Tunneling::updateAdditionalInfoTypesComboBox() model->item(0)->setEnabled(false); model->item(model->rowCount() - 1)->setEnabled(false); } + +void Tunneling::updateSecureConfigCombo() +{ + ui->secureSessionCb->clear(); + + ui->secureSessionCheckBox->setEnabled(!m_configs.isEmpty()); + ui->secureSessionCheckBox->setChecked(m_proto == QKnxNetIp::HostProtocol::TCP_IPv4); + + for (int i = 0; i < m_configs.size(); ++i) { + const auto &config = m_configs[i]; + if (m_server.individualAddress() != config.host()) + continue; + + const auto ia = config.individualAddress(); + ui->secureSessionCb->addItem(tr("User ID: %1 (Individual Address: %2)") + .arg(config.userId()) + .arg(ia.isValid() ? ia.toString() : tr("No specific address")), i); + } +} diff --git a/examples/knx/knxeditor/tunneling.h b/examples/knx/knxeditor/tunneling.h index 4431223..c95e41b 100644 --- a/examples/knx/knxeditor/tunneling.h +++ b/examples/knx/knxeditor/tunneling.h @@ -53,11 +53,11 @@ #include <QKnxControlField> #include <QKnxExtendedControlField> +#include <QKnxLinkLayerFrame> #include <QKnxNetIpTunnel> #include <QKnxNetIpServerInfo> -#include <QKnxLinkLayerFrame> -#include <QValidator> #include <QRegularExpression> +#include <QValidator> #include <QWidget> QT_BEGIN_NAMESPACE @@ -94,6 +94,7 @@ public: void setLocalAddress(const QHostAddress &address); void setKnxNetIpServer(const QKnxNetIpServerInfo &server); void setTcpEnable(bool value); + void onKeyringChanged(const QVector<QKnxNetIpSecureConfiguration> &configs); public slots: void clearLogging(); @@ -108,6 +109,7 @@ private: void setupApciTpciComboBox(); void setupMessageCodeComboBox(); void updateAdditionalInfoTypesComboBox(); + void updateSecureConfigCombo(); private: Ui::Tunneling *ui { nullptr }; @@ -119,6 +121,8 @@ private: QKnxNetIpTunnel m_tunnel; QKnxNetIpServerInfo m_server; QKnxNetIp::HostProtocol m_proto { QKnxNetIp::HostProtocol::UDP_IPv4 }; + QVector<QKnxNetIpSecureConfiguration> m_configs; + }; #endif diff --git a/examples/knx/knxeditor/tunneling.ui b/examples/knx/knxeditor/tunneling.ui index 072211b..ddf01a3 100644 --- a/examples/knx/knxeditor/tunneling.ui +++ b/examples/knx/knxeditor/tunneling.ui @@ -7,13 +7,13 @@ <x>0</x> <y>0</y> <width>856</width> - <height>385</height> + <height>404</height> </rect> </property> <property name="windowTitle"> <string>Form</string> </property> - <layout class="QVBoxLayout" name="verticalLayout_4" stretch="0,0,0,1,0"> + <layout class="QVBoxLayout" name="verticalLayout_2"> <item> <layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1,0,0,0,0,0"> <item> @@ -540,7 +540,7 @@ </layout> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_5"> + <layout class="QHBoxLayout" name="horizontalLayout_4"> <item> <widget class="QLabel" name="label_3"> <property name="sizePolicy"> @@ -608,26 +608,7 @@ </layout> </item> <item> - <widget class="QTextEdit" name="textOuputTunneling"> - <property name="focusPolicy"> - <enum>Qt::StrongFocus</enum> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::DefaultContextMenu</enum> - </property> - <property name="acceptDrops"> - <bool>false</bool> - </property> - <property name="undoRedoEnabled"> - <bool>false</bool> - </property> - <property name="readOnly"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_4"> + <layout class="QHBoxLayout" name="horizontalLayout_5"> <item> <widget class="QCheckBox" name="manualInput"> <property name="text"> @@ -636,7 +617,7 @@ </widget> </item> <item> - <spacer name="horizontalSpacer_3"> + <spacer name="horizontalSpacer_7"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> @@ -679,18 +660,70 @@ </item> <item> <widget class="QPushButton" name="tunnelingSendRequest"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> <property name="text"> <string>Send Request</string> </property> </widget> </item> + </layout> + </item> + <item> + <widget class="QTextEdit" name="textOuputTunneling"> + <property name="focusPolicy"> + <enum>Qt::StrongFocus</enum> + </property> + <property name="contextMenuPolicy"> + <enum>Qt::DefaultContextMenu</enum> + </property> + <property name="acceptDrops"> + <bool>false</bool> + </property> + <property name="undoRedoEnabled"> + <bool>false</bool> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QCheckBox" name="secureSessionCheckBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Use secure session</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="secureSessionCb"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> <item> <spacer name="horizontalSpacer_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> + <enum>QSizePolicy::Expanding</enum> </property> <property name="sizeHint" stdset="0"> <size> @@ -740,8 +773,6 @@ <tabstop>data</tabstop> <tabstop>manualInput</tabstop> <tabstop>tunnelingSendRequest</tabstop> - <tabstop>connectTunneling</tabstop> - <tabstop>disconnectTunneling</tabstop> </tabstops> <resources/> <connections> @@ -752,8 +783,8 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>16</x> - <y>364</y> + <x>26</x> + <y>282</y> </hint> <hint type="destinationlabel"> <x>23</x> @@ -768,8 +799,8 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>37</x> - <y>363</y> + <x>47</x> + <y>282</y> </hint> <hint type="destinationlabel"> <x>94</x> @@ -784,8 +815,8 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>58</x> - <y>361</y> + <x>68</x> + <y>282</y> </hint> <hint type="destinationlabel"> <x>42</x> @@ -800,8 +831,8 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>69</x> - <y>362</y> + <x>79</x> + <y>282</y> </hint> <hint type="destinationlabel"> <x>462</x> @@ -816,8 +847,8 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>14</x> - <y>359</y> + <x>24</x> + <y>282</y> </hint> <hint type="destinationlabel"> <x>576</x> @@ -832,8 +863,8 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>56</x> - <y>360</y> + <x>66</x> + <y>282</y> </hint> <hint type="destinationlabel"> <x>402</x> @@ -848,8 +879,8 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>57</x> - <y>364</y> + <x>67</x> + <y>282</y> </hint> <hint type="destinationlabel"> <x>706</x> @@ -864,8 +895,8 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>50</x> - <y>357</y> + <x>60</x> + <y>282</y> </hint> <hint type="destinationlabel"> <x>845</x> @@ -880,12 +911,12 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>29</x> - <y>355</y> + <x>39</x> + <y>282</y> </hint> <hint type="destinationlabel"> - <x>181</x> - <y>256</y> + <x>539</x> + <y>254</y> </hint> </hints> </connection> @@ -896,8 +927,8 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>79</x> - <y>355</y> + <x>89</x> + <y>282</y> </hint> <hint type="destinationlabel"> <x>680</x> @@ -912,12 +943,12 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>12</x> - <y>365</y> + <x>22</x> + <y>282</y> </hint> <hint type="destinationlabel"> - <x>19</x> - <y>251</y> + <x>280</x> + <y>254</y> </hint> </hints> </connection> @@ -928,12 +959,12 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>15</x> - <y>369</y> + <x>25</x> + <y>282</y> </hint> <hint type="destinationlabel"> - <x>116</x> - <y>245</y> + <x>411</x> + <y>254</y> </hint> </hints> </connection> @@ -944,12 +975,12 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>51</x> - <y>363</y> + <x>61</x> + <y>282</y> </hint> <hint type="destinationlabel"> - <x>416</x> - <y>256</y> + <x>36</x> + <y>254</y> </hint> </hints> </connection> @@ -960,12 +991,28 @@ <slot>setDisabled(bool)</slot> <hints> <hint type="sourcelabel"> - <x>51</x> - <y>363</y> + <x>61</x> + <y>282</y> + </hint> + <hint type="destinationlabel"> + <x>254</x> + <y>254</y> + </hint> + </hints> + </connection> + <connection> + <sender>secureSessionCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>secureSessionCb</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>75</x> + <y>384</y> </hint> <hint type="destinationlabel"> - <x>472</x> - <y>256</y> + <x>150</x> + <y>383</y> </hint> </hints> </connection> diff --git a/examples/knx/knxeditor/tunnelingfeatures.cpp b/examples/knx/knxeditor/tunnelingfeatures.cpp index 851cc5f..dedec6d 100644 --- a/examples/knx/knxeditor/tunnelingfeatures.cpp +++ b/examples/knx/knxeditor/tunnelingfeatures.cpp @@ -74,12 +74,21 @@ TunnelingFeatures::TunnelingFeatures(QWidget *parent) ui->featureValue->setEnabled(false); connect(ui->connectTunneling, &QPushButton::clicked, this, [&]() { - ui->textOuputTunneling->append(tr("Connecting to: %1 on port: %2 protocol: %3").arg(m_server - .controlEndpointAddress().toString()).arg(m_server.controlEndpointPort()).arg(int(m_protocol))); + ui->textOuputTunneling->append(tr("Connecting to: %1 on port: %2 protocol: %3") + .arg(m_server.controlEndpointAddress().toString()) + .arg(m_server.controlEndpointPort()).arg(int(m_protocol))); + m_tunnel.setLocalPort(0); - m_tunnel.connectToHost(m_server.controlEndpointAddress(), - m_server.controlEndpointPort(), - m_protocol); + if (ui->secureSessionCheckBox->isChecked()) { + auto config = m_configs.value(ui->secureSessionCb->currentIndex()); + config.setKeepSecureSessionAlive(true); + m_tunnel.setSecureConfiguration(config); + m_tunnel.connectToHostEncrypted(m_server.controlEndpointAddress(), + m_server.controlEndpointPort()); + } else { + m_tunnel.connectToHost(m_server.controlEndpointAddress(), + m_server.controlEndpointPort(), m_protocol); + } }); connect(ui->tunnelingSend, &QPushButton::clicked, this, [&]() { @@ -100,7 +109,7 @@ TunnelingFeatures::TunnelingFeatures(QWidget *parent) else if (type == ServType::TunnelingFeatureSet) m_tunnel.sendTunnelingFeatureSet(featureType, bytes); - ui->statusBar->setText(tr("Status: (%1) Messages sent.").arg(m_tunnel + ui->textOuputTunneling->append(tr("Status: (%1) Messages sent.").arg(m_tunnel .sequenceCount(QKnxNetIpEndpointConnection::SequenceType::Send) + 1)); }); @@ -190,7 +199,7 @@ TunnelingFeatures::TunnelingFeatures(QWidget *parent) ui->textOuputTunneling->append(tr("Successfully connected to: %1 on port: %2").arg(m_server .controlEndpointAddress().toString()).arg(m_server.controlEndpointPort())); - ui->statusBar->setText("Status: Connected."); + ui->textOuputTunneling->append("Status: Connected."); }); connect(ui->disconnectTunneling, &QPushButton::clicked, this, [&]() { @@ -206,7 +215,7 @@ TunnelingFeatures::TunnelingFeatures(QWidget *parent) ui->featureValue->setEnabled(false); ui->textOuputTunneling->append(tr("Successfully disconnected from: %1 on port: %2\n") .arg(m_server.controlEndpointAddress().toString()).arg(m_server.controlEndpointPort())); - ui->statusBar->setText("Status: Disconnected."); + ui->textOuputTunneling->append("Status: Disconnected."); }); connect(&m_tunnel, &QKnxNetIpTunnel::errorOccurred, this, @@ -217,10 +226,10 @@ TunnelingFeatures::TunnelingFeatures(QWidget *parent) connect(ui->tunnelServiceType, &QComboBox::currentTextChanged, this, [&](const QString &text) { if (text == QString("TunnelingFeatureSet")) { ui->featureValue->setEnabled(true); - ui->statusBar->setText("Status: Fill in the feature type and value fields."); + ui->textOuputTunneling->append("Status: Fill in the feature type and value fields."); } else { ui->featureValue->setEnabled(false); - ui->statusBar->setText(""); + ui->textOuputTunneling->append(""); } checkFeatureValue(); }); @@ -259,8 +268,10 @@ void TunnelingFeatures::setKnxNetIpServer(const QKnxNetIpServerInfo &server) ui->connectTunneling->setEnabled(true); ui->disconnectTunneling->setEnabled(false); } + + updateSecureConfigCombo(); ui->tunnelingSend->setEnabled(false); - ui->statusBar->setText("Status: Start by clicking connect."); + ui->textOuputTunneling->append("Status: Start by clicking connect."); } void TunnelingFeatures::setTcpEnable(bool value) @@ -268,10 +279,16 @@ void TunnelingFeatures::setTcpEnable(bool value) m_protocol = (value ? QKnxNetIp::HostProtocol::TCP_IPv4 : QKnxNetIp::HostProtocol::UDP_IPv4); } +void TunnelingFeatures::onKeyringChanged(const QVector<QKnxNetIpSecureConfiguration> &configs) +{ + m_configs = configs; + updateSecureConfigCombo(); +} + void TunnelingFeatures::checkFeatureValue() { if (!ui->featureValue->isEnabled()) { - ui->statusBar->setText(""); + ui->textOuputTunneling->append(""); ui->tunnelingSend->setEnabled(m_tunnel.state() == QKnxNetIpEndpointConnection::State::Connected); return; } @@ -289,10 +306,29 @@ void TunnelingFeatures::checkFeatureValue() auto text = ui->featureValue->text(); if (text.isEmpty() || !validFeature(type, featureType, bytes) || ((text.size() % 2) != 0)) { - ui->statusBar->setText("Status: Invalid value entered"); + ui->textOuputTunneling->append("Status: Invalid value entered"); ui->tunnelingSend->setEnabled(false); return; } - ui->statusBar->setText("Status: Valid value entered, click send."); + ui->textOuputTunneling->append("Status: Valid value entered, click send."); ui->tunnelingSend->setEnabled(m_tunnel.state() == QKnxNetIpEndpointConnection::State::Connected); } + +void TunnelingFeatures::updateSecureConfigCombo() +{ + ui->secureSessionCb->clear(); + + ui->secureSessionCheckBox->setEnabled(!m_configs.isEmpty()); + ui->secureSessionCheckBox->setChecked(m_protocol == QKnxNetIp::HostProtocol::TCP_IPv4); + + for (int i = 0; i < m_configs.size(); ++i) { + const auto &config = m_configs[i]; + if (m_server.individualAddress() != config.host()) + continue; + + const auto ia = config.individualAddress(); + ui->secureSessionCb->addItem(tr("User ID: %1 (Individual Address: %2)") + .arg(config.userId()) + .arg(ia.isValid() ? ia.toString() : tr("No specific address")), i); + } +} diff --git a/examples/knx/knxeditor/tunnelingfeatures.h b/examples/knx/knxeditor/tunnelingfeatures.h index 8c93667..162497e 100644 --- a/examples/knx/knxeditor/tunnelingfeatures.h +++ b/examples/knx/knxeditor/tunnelingfeatures.h @@ -53,15 +53,20 @@ public: void setLocalAddress(const QHostAddress &address); void setKnxNetIpServer(const QKnxNetIpServerInfo &server); void setTcpEnable(bool value); + void onKeyringChanged(const QVector<QKnxNetIpSecureConfiguration> &configs); private: void checkFeatureValue(); - Ui::TunnelingFeatures *ui; + void updateSecureConfigCombo(); + +private: + Ui::TunnelingFeatures *ui { nullptr }; QKnxNetIpServerInfo m_server; QKnxNetIpTunnel m_tunnel; QKnxNetIp::HostProtocol m_protocol = { QKnxNetIp::HostProtocol::UDP_IPv4 }; + QVector<QKnxNetIpSecureConfiguration> m_configs; }; #endif // TUNNELINGFEATURES_H diff --git a/examples/knx/knxeditor/tunnelingfeatures.ui b/examples/knx/knxeditor/tunnelingfeatures.ui index 50abfc8..112eb27 100644 --- a/examples/knx/knxeditor/tunnelingfeatures.ui +++ b/examples/knx/knxeditor/tunnelingfeatures.ui @@ -13,8 +13,8 @@ <property name="windowTitle"> <string>Form</string> </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0" colspan="4"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> <layout class="QGridLayout" name="gridLayout" columnstretch="0,1,0,0"> <item row="0" column="0"> <widget class="QLabel" name="label_13"> @@ -184,7 +184,7 @@ </item> </layout> </item> - <item row="1" column="0" colspan="4"> + <item> <widget class="QTextEdit" name="textOuputTunneling"> <property name="focusPolicy"> <enum>Qt::StrongFocus</enum> @@ -203,48 +203,93 @@ </property> </widget> </item> - <item row="2" column="0"> - <widget class="QLabel" name="statusBar"> - <property name="text"> - <string/> - </property> - </widget> - </item> - <item row="2" column="1"> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeType"> - <enum>QSizePolicy::Expanding</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>662</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="2" column="2"> - <widget class="QPushButton" name="connectTunneling"> - <property name="text"> - <string>Connect</string> - </property> - </widget> - </item> - <item row="2" column="3"> - <widget class="QPushButton" name="disconnectTunneling"> - <property name="text"> - <string>Disconnect</string> - </property> - </widget> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QCheckBox" name="secureSessionCheckBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Use secure session</string> + </property> + </widget> + </item> + <item> + <widget class="QComboBox" name="secureSessionCb"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>388</width> + <height>17</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="connectTunneling"> + <property name="text"> + <string>Connect</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="disconnectTunneling"> + <property name="text"> + <string>Disconnect</string> + </property> + </widget> + </item> + </layout> </item> </layout> </widget> <tabstops> + <tabstop>tunnelServiceType</tabstop> + <tabstop>featureIdentifier</tabstop> + <tabstop>featureValue</tabstop> + <tabstop>tunnelingSend</tabstop> + <tabstop>textOuputTunneling</tabstop> + <tabstop>secureSessionCheckBox</tabstop> + <tabstop>secureSessionCb</tabstop> + <tabstop>connectTunneling</tabstop> <tabstop>disconnectTunneling</tabstop> </tabstops> <resources/> - <connections/> + <connections> + <connection> + <sender>secureSessionCheckBox</sender> + <signal>toggled(bool)</signal> + <receiver>secureSessionCb</receiver> + <slot>setEnabled(bool)</slot> + <hints> + <hint type="sourcelabel"> + <x>42</x> + <y>363</y> + </hint> + <hint type="destinationlabel"> + <x>153</x> + <y>363</y> + </hint> + </hints> + </connection> + </connections> </ui> |