QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
RemoteTransport.cc
Go to the documentation of this file.
1#include "RemoteTransport.h"
2
3#include <QtCore/QtEndian>
4#include <QtNetwork/QHostAddress>
5#include <QtNetwork/QHostInfo>
6#include <QtNetwork/QSslConfiguration>
7#include <QtNetwork/QSslSocket>
8#include <QtNetwork/QUdpSocket>
9
10// --- UdpTransport ---
11
13 : RemoteTransport(parent)
14{
15}
16
17void UdpTransport::setTarget(const QString &host, quint16 port)
18{
19 _host = host;
20 _port = port;
21}
22
23bool UdpTransport::send(const QByteArray &data)
24{
25 if (!_socket) {
26 _socket = new QUdpSocket(this);
27 }
28
29 if (data.size() > kMaxDatagramSize) {
30 emit errorOccurred(tr("UDP payload too large (%1 bytes), dropped").arg(data.size()));
31 return false;
32 }
33
34 QHostAddress addr(_host);
35 if (addr.isNull()) {
36 // Resolve hostname to IP
37 const QHostInfo info = QHostInfo::fromName(_host);
38 if (info.error() != QHostInfo::NoError || info.addresses().isEmpty()) {
39 emit errorOccurred(tr("DNS resolution failed for '%1': %2").arg(_host, info.errorString()));
40 return false;
41 }
42 addr = info.addresses().first();
43 }
44 const qint64 written = _socket->writeDatagram(data, addr, _port);
45 if (written < 0) {
46 ++_failureCount;
47 emit errorOccurred(_socket->errorString());
48 return false;
49 }
50 return true;
51}
52
54{
55 if (_socket) {
56 _socket->deleteLater();
57 _socket = nullptr;
58 }
59 _failureCount = 0;
60}
61
62// --- TcpTransport ---
63
65 : RemoteTransport(parent)
66{
67}
68
69void TcpTransport::setTarget(const QString &host, quint16 port)
70{
71 _host = host;
72 _port = port;
73}
74
75void TcpTransport::setTlsEnabled(bool enabled) { _tlsEnabled = enabled; }
76void TcpTransport::setTlsVerifyPeer(bool verify) { _tlsVerifyPeer = verify; }
77void TcpTransport::setTlsCaCertificates(const QList<QSslCertificate> &certs) { _caCertificates = certs; }
78void TcpTransport::setTlsClientCertificate(const QSslCertificate &cert, const QSslKey &key)
79{
80 _clientCert = cert;
81 _clientKey = key;
82}
83
84bool TcpTransport::send(const QByteArray &data)
85{
86 if (!_socket || !_connected) {
87 return false;
88 }
89
90 QByteArray frame;
91 frame.reserve(4 + data.size());
92 const quint32 len = qToBigEndian(static_cast<quint32>(data.size()));
93 frame.append(reinterpret_cast<const char *>(&len), 4);
94 frame.append(data);
95
96 const qint64 written = _socket->write(frame);
97 if (written < 0) {
98 emit errorOccurred(_socket->errorString());
99 return false;
100 }
101 return true;
102}
103
105{
106 if (_socket) {
107 _socket->disconnect(this);
108 _socket->disconnectFromHost();
109 _socket->deleteLater();
110 _socket = nullptr;
111 }
112 if (_connected) {
113 _connected = false;
114 emit disconnected();
115 }
116}
117
119{
120 if (_socket && _socket->state() != QAbstractSocket::UnconnectedState) {
121 return;
122 }
123
124 _createSocket();
125
126 if (_tlsEnabled) {
127 _socket->connectToHostEncrypted(_host, _port);
128 } else {
129 _socket->connectToHost(_host, _port);
130 }
131}
132
133void TcpTransport::_createSocket()
134{
135 if (_socket) {
136 _socket->deleteLater();
137 _socket = nullptr;
138 }
139
140 _socket = new QSslSocket(this);
141
142 if (_tlsEnabled) {
143 QSslConfiguration config = QSslConfiguration::defaultConfiguration();
144 if (!_caCertificates.isEmpty()) {
145 config.setCaCertificates(_caCertificates);
146 }
147 if (!_clientCert.isNull()) {
148 config.setLocalCertificate(_clientCert);
149 config.setPrivateKey(_clientKey);
150 }
151 if (!_tlsVerifyPeer) {
152 config.setPeerVerifyMode(QSslSocket::VerifyNone);
153 }
154 _socket->setSslConfiguration(config);
155 connect(_socket, &QSslSocket::sslErrors, this, &TcpTransport::_onSslErrors);
156 }
157
158 connect(_socket, &QAbstractSocket::connected, this, &TcpTransport::_onConnected);
159 connect(_socket, &QAbstractSocket::disconnected, this, &TcpTransport::_onDisconnected);
160 connect(_socket, &QAbstractSocket::errorOccurred, this, &TcpTransport::_onError);
161}
162
163void TcpTransport::_onConnected()
164{
165 _connected = true;
166 emit connected();
167}
168
169void TcpTransport::_onDisconnected()
170{
171 _connected = false;
172 emit disconnected();
173}
174
175void TcpTransport::_onError(QAbstractSocket::SocketError)
176{
177 if (_socket) {
178 emit errorOccurred(_socket->errorString());
179 }
180}
181
182void TcpTransport::_onSslErrors(const QList<QSslError> &errors)
183{
184 QStringList messages;
185 for (const auto &err : errors) {
186 messages.append(err.errorString());
187 }
188 emit errorOccurred(QStringLiteral("TLS: ") + messages.join(QStringLiteral("; ")));
189
190 if (!_tlsVerifyPeer && _socket) {
191 // Only ignore certificate-related errors, not protocol/cipher failures
192 QList<QSslError> certErrors;
193 for (const auto &err : errors) {
194 switch (err.error()) {
195 case QSslError::SelfSignedCertificate:
196 case QSslError::SelfSignedCertificateInChain:
197 case QSslError::CertificateUntrusted:
198 case QSslError::CertificateNotYetValid:
199 case QSslError::CertificateExpired:
200 case QSslError::HostNameMismatch:
201 case QSslError::UnableToGetLocalIssuerCertificate:
202 case QSslError::UnableToVerifyFirstCertificate:
203 certErrors.append(err);
204 break;
205 default:
206 break;
207 }
208 }
209 if (!certErrors.isEmpty()) {
210 _socket->ignoreSslErrors(certErrors);
211 }
212 }
213}
void errorOccurred(const QString &message)
bool send(const QByteArray &data) override
void setTlsCaCertificates(const QList< QSslCertificate > &certs)
void close() override
void setTlsEnabled(bool enabled)
void setTlsVerifyPeer(bool verify)
void setTlsClientCertificate(const QSslCertificate &cert, const QSslKey &key)
TcpTransport(QObject *parent=nullptr)
void setTarget(const QString &host, quint16 port)
void close() override
bool send(const QByteArray &data) override
UdpTransport(QObject *parent=nullptr)
void setTarget(const QString &host, quint16 port)