From e97c05c2c9ba79276eb1790334bd2b4693d948e0 Mon Sep 17 00:00:00 2001 From: Alex Spataru Date: Thu, 21 Oct 2021 17:52:21 -0500 Subject: [PATCH] Add local/remote port for UDP connections --- assets/qml/Panes/Setup.qml | 18 +++- assets/qml/Panes/SetupPanes/Network.qml | 130 ++++++++++++++++++++---- src/IO/DataSources/Network.cpp | 91 ++++++++++++----- src/IO/DataSources/Network.h | 68 +++++++++---- src/IO/Manager.cpp | 2 +- 5 files changed, 237 insertions(+), 72 deletions(-) diff --git a/assets/qml/Panes/Setup.qml b/assets/qml/Panes/Setup.qml index a74f2cb3..7b2d196f 100644 --- a/assets/qml/Panes/Setup.qml +++ b/assets/qml/Panes/Setup.qml @@ -87,9 +87,11 @@ Item { // // Network settings // - property alias port: network.port property alias address: network.address + property alias tcpPort: network.tcpPort property alias socketType: network.socketType + property alias udpLocalPort: network.udpLocalPort + property alias udpRemotePort: network.udpRemotePort property alias udpMulticastEnabled: network.udpMulticastEnabled // @@ -300,10 +302,10 @@ Item { Layout.minimumHeight: implicitHeight Layout.maximumHeight: implicitHeight Layout.preferredHeight: implicitHeight - onCurrentIndexChanged: getImplicitHeight() - Component.onCompleted: getImplicitHeight() + onCurrentIndexChanged: updateHeight() + Component.onCompleted: updateHeight() - function getImplicitHeight() { + function updateHeight() { stack.implicitHeight = 0 switch (currentIndex) { @@ -335,6 +337,14 @@ Item { SetupPanes.Network { id: network + onUiChanged: timer.start() + + Timer { + id: timer + interval: 50 + onTriggered: stack.updateHeight() + } + background: TextField { enabled: false palette.base: Cpp_ThemeManager.setupPanelBackground diff --git a/assets/qml/Panes/SetupPanes/Network.qml b/assets/qml/Panes/SetupPanes/Network.qml index 3bf135dd..a629ac57 100644 --- a/assets/qml/Panes/SetupPanes/Network.qml +++ b/assets/qml/Panes/SetupPanes/Network.qml @@ -31,10 +31,17 @@ Control { // // Access to properties // - property alias port: _portText.text property alias address: _address.text + property alias tcpPort: _tcpPort.text + property alias udpLocalPort: _udpLocalPort.text + property alias udpRemotePort: _udpRemotePort.text property alias socketType: _typeCombo.currentIndex property alias udpMulticastEnabled: _udpMulticast.checked + + // + // Signals + // + signal uiChanged() // // React to network manager events @@ -42,14 +49,20 @@ Control { Connections { target: Cpp_IO_Network - function onHostChanged() { + function onAddressChanged() { if (_address.text.length > 0) - _address.text = Cpp_IO_Network.host + _address.text = Cpp_IO_Network.remoteAddress } function onPortChanged() { - if (_portText.text.length > 0) - _portText.text = Cpp_IO_Network.port + if (_tcpPort.text.length > 0) + _tcpPort.text = Cpp_IO_Network.tcpPort + + if (_udpLocalPort.text.length > 0) + _udpLocalPort.text = Cpp_IO_Network.udpLocalPort + + if (_udpRemotePort.text.length > 0) + _udpRemotePort.text = Cpp_IO_Network.udpRemotePort } } @@ -83,6 +96,8 @@ Control { onCurrentIndexChanged: { if (currentIndex !== Cpp_IO_Network.socketTypeIndex) Cpp_IO_Network.socketTypeIndex = currentIndex + + root.uiChanged() } opacity: enabled ? 1 : 0.5 @@ -97,18 +112,18 @@ Control { opacity: enabled ? 1 : 0.5 enabled: !Cpp_IO_Manager.connected Behavior on opacity {NumberAnimation{}} - text: qsTr("Host") + ":" + text: qsTr("Remote address") + ":" } TextField { id: _address Layout.fillWidth: true - placeholderText: Cpp_IO_Network.defaultHost - Component.onCompleted: text = Cpp_IO_Network.host + placeholderText: Cpp_IO_Network.defaultAddress + Component.onCompleted: text = Cpp_IO_Network.remoteAddress onTextChanged: { - if (Cpp_IO_Network.host !== text && text.length > 0) - Cpp_IO_Network.host = text + if (Cpp_IO_Network.remoteAddress !== text && text.length > 0) + Cpp_IO_Network.remoteAddress = text if (text.length === 0) - Cpp_IO_Network.host = Cpp_IO_Network.defaultHost + Cpp_IO_Network.remoteAddress = Cpp_IO_Network.defaultAddress } opacity: enabled ? 1 : 0.5 @@ -117,24 +132,25 @@ Control { } // - // Port + // TCP port // Label { opacity: enabled ? 1 : 0.5 + text: qsTr("Port") + ":" enabled: !Cpp_IO_Manager.connected Behavior on opacity {NumberAnimation{}} - text: qsTr("Port") + ":" + visible: Cpp_IO_Network.socketTypeIndex === 0 } TextField { - id: _portText + id: _tcpPort Layout.fillWidth: true - placeholderText: Cpp_IO_Network.defaultPort - Component.onCompleted: text = Cpp_IO_Network.port + placeholderText: Cpp_IO_Network.defaultTcpPort + Component.onCompleted: text = Cpp_IO_Network.tcpPort onTextChanged: { - if (Cpp_IO_Network.port !== text && text.length > 0) - Cpp_IO_Network.port = text + if (Cpp_IO_Network.tcpPort !== text && text.length > 0) + Cpp_IO_Network.tcpPort = text if (text.length === 0) - Cpp_IO_Network.port = Cpp_IO_Network.defaultPort + Cpp_IO_Network.port = Cpp_IO_Network.defaultTcpPort } validator: IntValidator { @@ -144,6 +160,77 @@ Control { opacity: enabled ? 1 : 0.5 enabled: !Cpp_IO_Manager.connected + visible: Cpp_IO_Network.socketTypeIndex === 0 + + Behavior on opacity {NumberAnimation{}} + } + + + // + // TCP port + // + Label { + opacity: enabled ? 1 : 0.5 + text: qsTr("Local port") + ":" + enabled: !Cpp_IO_Manager.connected + Behavior on opacity {NumberAnimation{}} + visible: Cpp_IO_Network.socketTypeIndex === 1 && !udpMulticastEnabled + } TextField { + id: _udpLocalPort + Layout.fillWidth: true + placeholderText: Cpp_IO_Network.defaultUdpLocalPort + Component.onCompleted: text = Cpp_IO_Network.udpLocalPort + onTextChanged: { + if (Cpp_IO_Network.udpLocalPort !== text && text.length > 0) + Cpp_IO_Network.udpLocalPort = text + + if (text.length === 0) + Cpp_IO_Network.udpLocalPort = Cpp_IO_Network.defaultUdpLocalPort + } + + validator: IntValidator { + bottom: 0 + top: 65535 + } + + opacity: enabled ? 1 : 0.5 + enabled: !Cpp_IO_Manager.connected + visible: Cpp_IO_Network.socketTypeIndex === 1 && !udpMulticastEnabled + + Behavior on opacity {NumberAnimation{}} + } + + // + // Output port + // + Label { + opacity: enabled ? 1 : 0.5 + text: qsTr("Remote port") + ":" + enabled: !Cpp_IO_Manager.connected + Behavior on opacity {NumberAnimation{}} + visible: Cpp_IO_Network.socketTypeIndex === 1 + } TextField { + id: _udpRemotePort + Layout.fillWidth: true + placeholderText: Cpp_IO_Network.defaultUdpRemotePort + Component.onCompleted: text = Cpp_IO_Network.udpRemotePort + onTextChanged: { + if (Cpp_IO_Network.udpRemotePort !== text && text.length > 0) + Cpp_IO_Network.udpRemotePort = text + + if (text.length === 0) + Cpp_IO_Network.udpRemotePort = Cpp_IO_Network.defaultUdpRemotePort + } + + validator: IntValidator { + bottom: 0 + top: 65535 + } + + opacity: enabled ? 1 : 0.5 + enabled: !Cpp_IO_Manager.connected + visible: Cpp_IO_Network.socketTypeIndex === 1 + Behavior on opacity {NumberAnimation{}} } @@ -154,16 +241,21 @@ Control { text: qsTr("Multicast") + ":" opacity: _udpMulticast.enabled ? 1 : 0.5 Behavior on opacity {NumberAnimation{}} + visible: Cpp_IO_Network.socketTypeIndex === 1 } CheckBox { id: _udpMulticast opacity: enabled ? 1 : 0.5 Layout.alignment: Qt.AlignLeft Layout.leftMargin: -app.spacing checked: Cpp_IO_Network.udpMulticast + visible: Cpp_IO_Network.socketTypeIndex === 1 enabled: Cpp_IO_Network.socketTypeIndex === 1 && !Cpp_IO_Manager.connected + onCheckedChanged: { if (Cpp_IO_Network.udpMulticast !== checked) Cpp_IO_Network.udpMulticast = checked + + root.uiChanged() } Behavior on opacity {NumberAnimation{}} diff --git a/src/IO/DataSources/Network.cpp b/src/IO/DataSources/Network.cpp index c60481c6..c7dd6c66 100644 --- a/src/IO/DataSources/Network.cpp +++ b/src/IO/DataSources/Network.cpp @@ -36,8 +36,10 @@ Network::Network() , m_udpMulticast(false) , m_lookupActive(false) { - setHost(""); - setPort(defaultPort()); + setRemoteAddress(""); + setTcpPort(defaultTcpPort()); + setUdpLocalPort(defaultUdpLocalPort()); + setUdpRemotePort(defaultUdpRemotePort()); setSocketType(QAbstractSocket::TcpSocket); connect(&m_tcpSocket, &QTcpSocket::errorOccurred, this, &Network::onErrorOccurred); connect(&m_udpSocket, &QUdpSocket::errorOccurred, this, &Network::onErrorOccurred); @@ -65,17 +67,33 @@ Network *Network::getInstance() /** * Returns the host address */ -QString Network::host() const +QString Network::remoteAddress() const { - return m_host; + return m_address; } /** - * Returns the network port number + * Returns the TCP port number */ -quint16 Network::port() const +quint16 Network::tcpPort() const { - return m_port; + return m_tcpPort; +} + +/** + * Returns the UDP local port number + */ +quint16 Network::udpLocalPort() const +{ + return m_udpLocalPort; +} + +/** + * Returns the UDP remote port number + */ +quint16 Network::udpRemotePort() const +{ + return m_udpRemotePort; } /** @@ -120,7 +138,7 @@ int Network::socketTypeIndex() const */ bool Network::configurationOk() const { - return port() > 0 && m_hostExists; + return tcpPort() > 0 && m_hostExists; } /** @@ -156,18 +174,15 @@ QIODevice *Network::openNetworkPort() QAbstractSocket *socket = nullptr; // Get host & port - auto hostAddr = host(); - auto portAddr = port(); + auto hostAddr = remoteAddress(); if (hostAddr.isEmpty()) - hostAddr = defaultHost(); - if (portAddr <= 0) - portAddr = defaultPort(); + hostAddr = defaultAddress(); // TCP connection, assign socket pointer & connect to host if (socketType() == QAbstractSocket::TcpSocket) { socket = &m_tcpSocket; - m_tcpSocket.connectToHost(hostAddr, portAddr); + m_tcpSocket.connectToHost(hostAddr, tcpPort()); } // UDP connection, assign socket pointer & bind to host @@ -178,20 +193,24 @@ QIODevice *Network::openNetworkPort() { QHostAddress address(hostAddr); if (address.protocol() == QAbstractSocket::IPv4Protocol) - m_udpSocket.bind(QHostAddress::AnyIPv4, portAddr, + m_udpSocket.bind(QHostAddress::AnyIPv4, udpRemotePort(), QUdpSocket::ShareAddress); else if (address.protocol() == QAbstractSocket::IPv6Protocol) - m_udpSocket.bind(QHostAddress::AnyIPv6, portAddr, + m_udpSocket.bind(QHostAddress::AnyIPv6, udpRemotePort(), QUdpSocket::ShareAddress); else - m_udpSocket.bind(QHostAddress::Any, portAddr, QUdpSocket::ShareAddress); + m_udpSocket.bind(QHostAddress::Any, udpRemotePort(), + QUdpSocket::ShareAddress); m_udpSocket.joinMulticastGroup(address); } // Bind the UDP socket to an individual host else - m_udpSocket.connectToHost(hostAddr, portAddr); + { + m_udpSocket.bind(QHostAddress::LocalHost, udpLocalPort()); + m_udpSocket.connectToHost(hostAddr, udpRemotePort()); + } // Update socket pointer socket = &m_udpSocket; @@ -227,24 +246,42 @@ void Network::disconnectDevice() } /** - * Sets the @c port number + * Changes the TCP socket's @c port number */ -void Network::setPort(const quint16 port) +void Network::setTcpPort(const quint16 port) { - m_port = port; + m_tcpPort = port; + emit portChanged(); +} + +/** + * Changes the UDP socket's local @c port number + */ +void Network::setUdpLocalPort(const quint16 port) +{ + m_udpLocalPort = port; + emit portChanged(); +} + +/** + * Changes the UDP socket's remote @c port number + */ +void Network::setUdpRemotePort(const quint16 port) +{ + m_udpRemotePort = port; emit portChanged(); } /** * Sets the IPv4 or IPv6 address specified by the input string representation */ -void Network::setHost(const QString &host) +void Network::setRemoteAddress(const QString &address) { // Check if host name exists - if (QHostAddress(host).isNull()) + if (QHostAddress(address).isNull()) { m_hostExists = false; - lookup(host); + lookup(address); } // Host is an IP address, host should exist @@ -252,8 +289,8 @@ void Network::setHost(const QString &host) m_hostExists = true; // Change host - m_host = host; - emit hostChanged(); + m_address = address; + emit addressChanged(); } /** @@ -323,7 +360,7 @@ void Network::lookupFinished(const QHostInfo &info) if (addresses.count() >= 1) { m_hostExists = true; - emit hostChanged(); + emit addressChanged(); return; } } diff --git a/src/IO/DataSources/Network.h b/src/IO/DataSources/Network.h index f1f0fc1b..6ac18bc9 100644 --- a/src/IO/DataSources/Network.h +++ b/src/IO/DataSources/Network.h @@ -43,13 +43,21 @@ class Network : public QObject { // clang-format off Q_OBJECT - Q_PROPERTY(QString host - READ host - WRITE setHost - NOTIFY hostChanged) - Q_PROPERTY(quint16 port - READ port - WRITE setPort + Q_PROPERTY(QString remoteAddress + READ remoteAddress + WRITE setRemoteAddress + NOTIFY addressChanged) + Q_PROPERTY(quint16 tcpPort + READ tcpPort + WRITE setTcpPort + NOTIFY portChanged) + Q_PROPERTY(quint16 udpLocalPort + READ udpLocalPort + WRITE setUdpLocalPort + NOTIFY portChanged) + Q_PROPERTY(quint16 udpRemotePort + READ udpRemotePort + WRITE setUdpRemotePort NOTIFY portChanged) Q_PROPERTY(QAbstractSocket::SocketType socketType READ socketType @@ -62,11 +70,17 @@ class Network : public QObject Q_PROPERTY(QVector socketTypes READ socketTypes CONSTANT) - Q_PROPERTY(QString defaultHost - READ defaultHost + Q_PROPERTY(QString defaultAddress + READ defaultAddress CONSTANT) - Q_PROPERTY(quint16 defaultPort - READ defaultPort + Q_PROPERTY(quint16 defaultTcpPort + READ defaultTcpPort + CONSTANT) + Q_PROPERTY(quint16 defaultUdpLocalPort + READ defaultUdpLocalPort + CONSTANT) + Q_PROPERTY(quint16 defaultUdpRemotePort + READ defaultUdpRemotePort CONSTANT) Q_PROPERTY(bool lookupActive READ lookupActive @@ -78,8 +92,8 @@ class Network : public QObject // clang-format on signals: - void hostChanged(); void portChanged(); + void addressChanged(); void socketTypeChanged(); void udpMulticastChanged(); void lookupActiveChanged(); @@ -87,8 +101,12 @@ signals: public: static Network *getInstance(); - QString host() const; - quint16 port() const; + QString remoteAddress() const; + + quint16 tcpPort() const; + quint16 udpLocalPort() const; + quint16 udpRemotePort() const; + bool udpMulticast() const; bool lookupActive() const; int socketTypeIndex() const; @@ -98,8 +116,11 @@ public: QTcpSocket *tcpSocket() { return &m_tcpSocket; } QUdpSocket *udpSocket() { return &m_udpSocket; } - static QString defaultHost() { return "127.0.0.1"; } - static quint16 defaultPort() { return 23; } + + static QString defaultAddress() { return "127.0.0.1"; } + static quint16 defaultTcpPort() { return 23; } + static quint16 defaultUdpRemotePort() { return 53; } + static quint16 defaultUdpLocalPort() { return 8888; } QIODevice *openNetworkPort(); @@ -107,11 +128,13 @@ public slots: void setTcpSocket(); void setUdpSocket(); void disconnectDevice(); - void setPort(const quint16 port); - void setHost(const QString &host); void lookup(const QString &host); + void setTcpPort(const quint16 port); + void setUdpLocalPort(const quint16 port); void setUdpMulticast(const bool enabled); void setSocketTypeIndex(const int index); + void setUdpRemotePort(const quint16 port); + void setRemoteAddress(const QString &address); void setSocketType(const QAbstractSocket::SocketType type); private slots: @@ -123,15 +146,18 @@ private: ~Network(); private: - QString m_host; - quint16 m_port; + QString m_address; + quint16 m_tcpPort; bool m_hostExists; bool m_udpMulticast; bool m_lookupActive; QIODevice *m_device; + quint16 m_udpLocalPort; + quint16 m_udpRemotePort; + QAbstractSocket::SocketType m_socketType; + QTcpSocket m_tcpSocket; QUdpSocket m_udpSocket; - QAbstractSocket::SocketType m_socketType; }; } } diff --git a/src/IO/Manager.cpp b/src/IO/Manager.cpp index 7973772a..26091130 100644 --- a/src/IO/Manager.cpp +++ b/src/IO/Manager.cpp @@ -79,8 +79,8 @@ Manager::Manager() // Configure signals/slots auto serial = DataSources::Serial::getInstance(); auto netwrk = DataSources::Network::getInstance(); - connect(netwrk, SIGNAL(hostChanged()), this, SIGNAL(configurationChanged())); connect(netwrk, SIGNAL(portChanged()), this, SIGNAL(configurationChanged())); + connect(netwrk, SIGNAL(addressChanged()), this, SIGNAL(configurationChanged())); connect(this, SIGNAL(dataSourceChanged()), this, SIGNAL(configurationChanged())); connect(serial, SIGNAL(portIndexChanged()), this, SIGNAL(configurationChanged())); }