summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarsten Heimrich <karsten.heimrich@qt.io>2019-03-28 16:29:41 +0100
committerKarsten Heimrich <karsten.heimrich@qt.io>2019-03-29 11:55:02 +0000
commit272249ce5bd5cd08082f2a00944fa92ef12c3076 (patch)
tree9132d88919ef8b35c9121bb48f69d37d62da53b9
parent2e67dd4c5eb463bd71fe8c382b45fc3c0eb47403 (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.cpp43
-rw-r--r--examples/knx/knxeditor/localdevicemanagement.h5
-rw-r--r--examples/knx/knxeditor/localdevicemanagement.ui61
-rw-r--r--examples/knx/knxeditor/mainwindow.cpp31
-rw-r--r--examples/knx/knxeditor/mainwindow.h4
-rw-r--r--examples/knx/knxeditor/mainwindow.ui13
-rw-r--r--examples/knx/knxeditor/tunneling.cpp52
-rw-r--r--examples/knx/knxeditor/tunneling.h8
-rw-r--r--examples/knx/knxeditor/tunneling.ui177
-rw-r--r--examples/knx/knxeditor/tunnelingfeatures.cpp64
-rw-r--r--examples/knx/knxeditor/tunnelingfeatures.h7
-rw-r--r--examples/knx/knxeditor/tunnelingfeatures.ui125
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>