feat(ipc): Unrecognised IPC client, retry messages, and TLS fingerprint
Also adds version checking for IPC server and client
This commit is contained in:
parent
66c9b6607c
commit
59a4747113
28 changed files with 170 additions and 826 deletions
|
|
@ -14,7 +14,6 @@
|
|||
#include "base/NetworkProtocol.h"
|
||||
#include "client/ServerProxy.h"
|
||||
#include "common/Settings.h"
|
||||
#include "deskflow/ipc/CoreIpc.h"
|
||||
#include "deskflow/Clipboard.h"
|
||||
#include "deskflow/IPlatformScreen.h"
|
||||
#include "deskflow/PacketStreamFilter.h"
|
||||
|
|
@ -22,11 +21,14 @@
|
|||
#include "deskflow/ProtocolUtil.h"
|
||||
#include "deskflow/Screen.h"
|
||||
#include "deskflow/StreamChunker.h"
|
||||
#include "deskflow/ipc/CoreIpc.h"
|
||||
#include "net/IDataSocket.h"
|
||||
#include "net/ISocketFactory.h"
|
||||
#include "net/SecureSocket.h"
|
||||
#include "net/TCPSocket.h"
|
||||
|
||||
#include <QMetaEnum>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
|
|
@ -133,8 +135,11 @@ void Client::disconnect(const char *msg)
|
|||
}
|
||||
}
|
||||
|
||||
void Client::refuseConnection(const char *msg)
|
||||
void Client::refuseConnection(deskflow::core::ConnectionRefusal reason, const char *msg)
|
||||
{
|
||||
const auto metaEnum = QMetaEnum::fromType<deskflow::core::ConnectionRefusal>();
|
||||
ipcSendToClient("connectionRefused", metaEnum.valueToKey(static_cast<int>(reason)));
|
||||
|
||||
cleanup();
|
||||
|
||||
if (msg) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include "deskflow/IClient.h"
|
||||
|
||||
#include "base/EventTypes.h"
|
||||
#include "common/Enums.h"
|
||||
#include "deskflow/IClipboard.h"
|
||||
#include "net/NetworkAddress.h"
|
||||
|
||||
|
|
@ -88,7 +89,7 @@ public:
|
|||
Disconnects from the server with an optional error message.
|
||||
Unlike disconnect this function doesn't try to use other ip addresses
|
||||
*/
|
||||
void refuseConnection(const char *msg);
|
||||
void refuseConnection(deskflow::core::ConnectionRefusal reason, const char *msg);
|
||||
|
||||
//! Notify of handshake complete
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ void ServerProxy::handleData()
|
|||
ServerProxy::ConnectionResult ServerProxy::parseHandshakeMessage(const uint8_t *code)
|
||||
{
|
||||
using enum ConnectionResult;
|
||||
using enum deskflow::core::ConnectionRefusal;
|
||||
|
||||
if (memcmp(code, kMsgQInfo, 4) == 0) {
|
||||
queryInfo();
|
||||
|
|
@ -168,25 +169,25 @@ ServerProxy::ConnectionResult ServerProxy::parseHandshakeMessage(const uint8_t *
|
|||
int32_t minor;
|
||||
ProtocolUtil::readf(m_stream, kMsgEIncompatible + 4, &major, &minor);
|
||||
LOG_ERR("server has incompatible version %d.%d", major, minor);
|
||||
m_client->refuseConnection("server has incompatible version");
|
||||
m_client->refuseConnection(IncompatibleVersion, "server has incompatible version");
|
||||
return Disconnect;
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgEBusy, 4) == 0) {
|
||||
LOG_ERR("server already has a connected client with name \"%s\"", m_client->getName().c_str());
|
||||
m_client->refuseConnection("server already has a connected client with our name");
|
||||
m_client->refuseConnection(AlreadyConnected, "server already has a connected client with our name");
|
||||
return Disconnect;
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgEUnknown, 4) == 0) {
|
||||
LOG_ERR("server refused client with name \"%s\"", m_client->getName().c_str());
|
||||
m_client->refuseConnection("server refused client with our name");
|
||||
m_client->refuseConnection(UnknownClient, "server refused client with our name");
|
||||
return Disconnect;
|
||||
}
|
||||
|
||||
else if (memcmp(code, kMsgEBad, 4) == 0) {
|
||||
LOG_ERR("server disconnected due to a protocol error");
|
||||
m_client->refuseConnection("server reported a protocol error");
|
||||
m_client->refuseConnection(ProtocolError, "server reported a protocol error");
|
||||
return Disconnect;
|
||||
} else if (memcmp(code, kMsgDLanguageSynchronisation, 4) == 0) {
|
||||
setServerLanguages();
|
||||
|
|
|
|||
|
|
@ -43,4 +43,14 @@ enum class ConnectionState
|
|||
Listening
|
||||
};
|
||||
Q_ENUM_NS(ConnectionState)
|
||||
|
||||
enum class ConnectionRefusal
|
||||
{
|
||||
IncompatibleVersion,
|
||||
AlreadyConnected,
|
||||
UnknownClient,
|
||||
ProtocolError
|
||||
};
|
||||
Q_ENUM_NS(ConnectionRefusal)
|
||||
|
||||
} // namespace deskflow::core
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include "IpcServer.h"
|
||||
|
||||
#include "base/Log.h"
|
||||
#include "common/VersionInfo.h"
|
||||
|
||||
#include <QLocalServer>
|
||||
#include <QLocalSocket>
|
||||
|
|
@ -110,8 +111,21 @@ void IpcServer::processMessage(QLocalSocket *clientSocket, const QString &messag
|
|||
}
|
||||
|
||||
if (const auto &command = parts.at(0); command == "hello") {
|
||||
const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha);
|
||||
const auto clientVersion = parts.size() >= 2 ? parts.at(1) : QString();
|
||||
if (clientVersion != versionId) {
|
||||
LOG_ERR(
|
||||
"ipc client version mismatch (client: %s, server: %s)",
|
||||
clientVersion.isEmpty() ? "unknown" : clientVersion.toUtf8().constData(), versionId.toUtf8().constData()
|
||||
);
|
||||
writeToClientSocket(clientSocket, "error");
|
||||
clientSocket->flush();
|
||||
clientSocket->disconnectFromServer();
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("ipc server got hello message, sending hello back");
|
||||
writeToClientSocket(clientSocket, "hello");
|
||||
writeToClientSocket(clientSocket, QString("hello=%1").arg(versionId));
|
||||
|
||||
// Replay messages that were queued before any clients connected.
|
||||
LOG_DEBUG1("ipc server replaying %d pending messages", m_pendingMessages.size());
|
||||
|
|
|
|||
|
|
@ -39,7 +39,6 @@ add_library(${target} STATIC
|
|||
TlsUtility.h
|
||||
VersionChecker.cpp
|
||||
VersionChecker.h
|
||||
config/IServerConfig.h
|
||||
config/Screen.cpp
|
||||
config/Screen.h
|
||||
config/ScreenConfig.cpp
|
||||
|
|
@ -48,16 +47,10 @@ add_library(${target} STATIC
|
|||
config/ScreenList.h
|
||||
config/ServerConfig.cpp
|
||||
config/ServerConfig.h
|
||||
core/ClientConnection.cpp
|
||||
core/ClientConnection.h
|
||||
core/CoreProcess.cpp
|
||||
core/CoreProcess.h
|
||||
core/NetworkMonitor.cpp
|
||||
core/NetworkMonitor.h
|
||||
core/ServerConnection.cpp
|
||||
core/ServerConnection.h
|
||||
core/ServerMessage.cpp
|
||||
core/ServerMessage.h
|
||||
dialogs/AboutDialog.cpp
|
||||
dialogs/AboutDialog.h
|
||||
dialogs/AboutDialog.ui
|
||||
|
|
|
|||
|
|
@ -58,8 +58,6 @@ using namespace deskflow::gui;
|
|||
MainWindow::MainWindow()
|
||||
: ui{std::make_unique<Ui::MainWindow>()},
|
||||
m_coreProcess(m_serverConfig),
|
||||
m_serverConnection(this, m_serverConfig),
|
||||
m_clientConnection(this),
|
||||
m_trayIcon{new QSystemTrayIcon(this)},
|
||||
m_guiDupeChecker{new QLocalServer(this)},
|
||||
m_daemonIpcClient{new ipc::DaemonIpcClient(this)},
|
||||
|
|
@ -269,15 +267,11 @@ void MainWindow::connectSlots()
|
|||
if (!deskflow::platform::isMac())
|
||||
connect(m_trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivated);
|
||||
|
||||
connect(&m_serverConnection, &ServerConnection::configureClient, this, &MainWindow::serverConnectionConfigureClient);
|
||||
connect(&m_serverConnection, &ServerConnection::clientsChanged, this, &MainWindow::serverClientsChanged);
|
||||
connect(&m_coreProcess, &CoreProcess::connectedClientsChanged, this, &MainWindow::serverClientsChanged);
|
||||
connect(
|
||||
&m_serverConnection, &ServerConnection::requestNewClientPrompt, this, &MainWindow::handleNewClientPromptRequest
|
||||
);
|
||||
|
||||
connect(&m_clientConnection, &ClientConnection::requestShowError, this, &MainWindow::showClientError);
|
||||
connect(&m_clientConnection, &ClientConnection::updateTimeoutDelay, this, &MainWindow::updateTimeoutDelay);
|
||||
connect(&m_coreProcess, &CoreProcess::unrecognisedClient, this, &MainWindow::handleUnrecognisedClient);
|
||||
connect(&m_coreProcess, &CoreProcess::connectionRefused, this, &MainWindow::handleConnectionRefused);
|
||||
connect(&m_coreProcess, &CoreProcess::retryIn, this, &MainWindow::updateTimeoutDelay);
|
||||
connect(&m_coreProcess, &CoreProcess::peerFingerprint, this, &MainWindow::handlePeerFingerprint);
|
||||
|
||||
if (Settings::value(Settings::Gui::AutoStartCore).toBool()) {
|
||||
connect(ui->btnToggleCore, &QPushButton::clicked, m_actionStopCore, &QAction::trigger, Qt::UniqueConnection);
|
||||
|
|
@ -430,8 +424,6 @@ void MainWindow::clearSettings()
|
|||
m_networkMonitor->stopMonitoring();
|
||||
|
||||
disconnect(&m_coreProcess, nullptr, this, nullptr);
|
||||
disconnect(&m_serverConnection, nullptr, this, nullptr);
|
||||
disconnect(&m_clientConnection, nullptr, this, nullptr);
|
||||
disconnect(&m_versionChecker, nullptr, this, nullptr);
|
||||
disconnect(m_guiDupeChecker, nullptr, this, nullptr);
|
||||
disconnect(m_trayIcon, nullptr, this, nullptr);
|
||||
|
|
@ -598,12 +590,12 @@ void MainWindow::updateNetworkInfo()
|
|||
|
||||
void MainWindow::serverConnectionConfigureClient(const QString &clientName)
|
||||
{
|
||||
m_serverConnection.serverConfigDialogVisible(true);
|
||||
m_serverConfigDialogVisible = true;
|
||||
ServerConfigDialog dialog(this, m_serverConfig);
|
||||
if (dialog.addClient(clientName) && dialog.exec() == QDialog::Accepted) {
|
||||
m_coreProcess.restart();
|
||||
}
|
||||
m_serverConnection.serverConfigDialogVisible(false);
|
||||
m_serverConfigDialogVisible = false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -755,35 +747,64 @@ void MainWindow::setTrayIcon()
|
|||
void MainWindow::handleLogLine(const QString &line)
|
||||
{
|
||||
m_logDock->appendLine(line);
|
||||
updateFromLogLine(line);
|
||||
}
|
||||
|
||||
void MainWindow::updateFromLogLine(const QString &line)
|
||||
void MainWindow::handleUnrecognisedClient(const QString &clientName)
|
||||
{
|
||||
checkConnected(line);
|
||||
checkFingerprint(line);
|
||||
}
|
||||
|
||||
void MainWindow::checkConnected(const QString &line)
|
||||
{
|
||||
if (ui->rbModeServer->isChecked()) {
|
||||
m_serverConnection.handleLogLine(line);
|
||||
} else {
|
||||
m_clientConnection.handleLogLine(line);
|
||||
if (m_ignoredClients.contains(clientName)) {
|
||||
qDebug("ignoring %s:", qPrintable(clientName));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::checkFingerprint(const QString &line)
|
||||
{
|
||||
static const auto tlsPeerMessage = QStringLiteral("peer fingerprint: ");
|
||||
static const qsizetype msgLen = QString(tlsPeerMessage).length();
|
||||
|
||||
const qsizetype midStart = line.indexOf(tlsPeerMessage);
|
||||
if (midStart == -1)
|
||||
if (m_newClientPromptShowing || m_serverConfigDialogVisible)
|
||||
return;
|
||||
|
||||
const auto sha256Text = line.mid(midStart + msgLen).remove(':');
|
||||
if (Settings::value(Settings::Server::ExternalConfig).toBool())
|
||||
return;
|
||||
|
||||
if (m_serverConfig.isFull() || m_serverConfig.screenExists(clientName))
|
||||
return;
|
||||
|
||||
m_newClientPromptShowing = true;
|
||||
|
||||
showAndActivate();
|
||||
|
||||
if (deskflow::gui::messages::showNewClientPrompt(this, clientName)) {
|
||||
serverConnectionConfigureClient(clientName);
|
||||
} else {
|
||||
m_ignoredClients.insert(clientName);
|
||||
}
|
||||
|
||||
m_newClientPromptShowing = false;
|
||||
}
|
||||
|
||||
void MainWindow::handleConnectionRefused(deskflow::core::ConnectionRefusal reason)
|
||||
{
|
||||
if (reason != deskflow::core::ConnectionRefusal::AlreadyConnected)
|
||||
return;
|
||||
|
||||
if (!isVisible() || m_clientErrorVisible)
|
||||
return;
|
||||
|
||||
m_clientErrorVisible = true;
|
||||
showAndActivate();
|
||||
|
||||
const auto address = Settings::value(Settings::Client::RemoteHost).toString();
|
||||
QMessageBox::warning(
|
||||
this, tr("%1 Connection Error").arg(kAppName),
|
||||
tr("<p>Failed to connect to the server '%1'.</p>"
|
||||
"<p>A Client with your name is already connected to the server.</p>"
|
||||
"Please ensure that you're using a unique name and that only a "
|
||||
"single instance of the client process is running.</p>")
|
||||
.arg(address)
|
||||
);
|
||||
|
||||
m_clientErrorVisible = false;
|
||||
}
|
||||
|
||||
void MainWindow::handlePeerFingerprint(const QString &fingerprint)
|
||||
{
|
||||
const auto sha256Text = QString(fingerprint).remove(':');
|
||||
const Fingerprint sha256 = {QCryptographicHash::Sha256, QByteArray::fromHex(sha256Text.toLatin1())};
|
||||
|
||||
const bool isClient = m_coreProcess.mode() == CoreMode::Client;
|
||||
|
|
@ -959,7 +980,7 @@ void MainWindow::changeEvent(QEvent *e)
|
|||
updateModeControlLabels();
|
||||
updateNetworkInfo();
|
||||
updateStatus();
|
||||
serverClientsChanged(m_serverConnection.connectedClients());
|
||||
serverClientsChanged({});
|
||||
updateText();
|
||||
}
|
||||
}
|
||||
|
|
@ -1167,34 +1188,6 @@ void MainWindow::remoteHostChanged(const QString &newRemoteHost)
|
|||
}
|
||||
}
|
||||
|
||||
void MainWindow::showClientError(deskflow::client::ErrorType error, const QString &address)
|
||||
{
|
||||
if (!isVisible() || m_clientErrorVisible || error != deskflow::client::ErrorType::AlreadyConnected)
|
||||
return;
|
||||
|
||||
m_clientErrorVisible = true;
|
||||
|
||||
showAndActivate();
|
||||
|
||||
QMessageBox::warning(
|
||||
this, tr("%1 Connection Error").arg(kAppName),
|
||||
tr("<p>Failed to connect to the server '%1'.</p>"
|
||||
"<p>A Client with your name is already connected to the server.</p>"
|
||||
"Please ensure that you're using a unique name and that only a "
|
||||
"single instance of the client process is running.</p>")
|
||||
.arg(address)
|
||||
);
|
||||
|
||||
m_clientErrorVisible = false;
|
||||
}
|
||||
|
||||
void MainWindow::handleNewClientPromptRequest(const QString &clientName)
|
||||
{
|
||||
showAndActivate();
|
||||
bool result = deskflow::gui::messages::showNewClientPrompt(this, clientName);
|
||||
m_serverConnection.handleNewClientResult(clientName, result);
|
||||
}
|
||||
|
||||
void MainWindow::updateIpLabel(const QStringList &addresses)
|
||||
{
|
||||
if (m_coreProcess.mode() != CoreMode::Server) {
|
||||
|
|
|
|||
|
|
@ -16,10 +16,8 @@
|
|||
|
||||
#include "VersionChecker.h"
|
||||
#include "config/ServerConfig.h"
|
||||
#include "gui/core/ClientConnection.h"
|
||||
#include "gui/core/CoreProcess.h"
|
||||
#include "gui/core/NetworkMonitor.h"
|
||||
#include "gui/core/ServerConnection.h"
|
||||
#include "net/Fingerprint.h"
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
|
|
@ -118,9 +116,9 @@ private:
|
|||
void setupTrayIcon();
|
||||
void applyConfig();
|
||||
void setTrayIcon();
|
||||
void updateFromLogLine(const QString &line);
|
||||
void checkConnected(const QString &line);
|
||||
void checkFingerprint(const QString &line);
|
||||
void handleUnrecognisedClient(const QString &clientName);
|
||||
void handleConnectionRefused(deskflow::core::ConnectionRefusal reason);
|
||||
void handlePeerFingerprint(const QString &fingerprint);
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void secureSocket(bool secureSocket);
|
||||
void connectSlots();
|
||||
|
|
@ -140,17 +138,10 @@ private:
|
|||
void daemonIpcClientConnectionFailed();
|
||||
void toggleCanRunCore(bool enableButtons);
|
||||
void remoteHostChanged(const QString &newRemoteHost);
|
||||
void handleNewClientPromptRequest(const QString &clientName);
|
||||
void updateIpLabel(const QStringList &addresses);
|
||||
void updateTimeoutDelay(int newDelay);
|
||||
|
||||
bool canRunCore() const;
|
||||
/**
|
||||
* @brief showClientError
|
||||
* @param error Error Type
|
||||
* @param address
|
||||
*/
|
||||
void showClientError(deskflow::client::ErrorType error, const QString &address);
|
||||
|
||||
/**
|
||||
* @brief trustedFingerprintDatabase get the FingerprintDatabase for the trusted clients or trusted servers.
|
||||
|
|
@ -177,8 +168,9 @@ private:
|
|||
bool m_clientErrorVisible = false;
|
||||
ServerConfig m_serverConfig;
|
||||
deskflow::gui::CoreProcess m_coreProcess;
|
||||
deskflow::gui::ServerConnection m_serverConnection;
|
||||
deskflow::gui::ClientConnection m_clientConnection;
|
||||
QSet<QString> m_ignoredClients;
|
||||
bool m_newClientPromptShowing = false;
|
||||
bool m_serverConfigDialogVisible = false;
|
||||
QSize m_expandedSize = QSize();
|
||||
QStringList m_checkedClients;
|
||||
QStringList m_checkedServers;
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2024 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
|
||||
#include "ScreenList.h"
|
||||
|
||||
namespace deskflow::gui {
|
||||
|
||||
// TODO: Remove this class, when the ServerConnectionTests are ported to QTests
|
||||
class IServerConfig
|
||||
{
|
||||
public:
|
||||
virtual ~IServerConfig() = default;
|
||||
virtual bool isFull() const = 0;
|
||||
virtual bool screenExists(const QString &screenName) const = 0;
|
||||
virtual bool save(const QString &fileName) const = 0;
|
||||
virtual void save(QFile &file) const = 0;
|
||||
virtual const ScreenList &screens() const = 0;
|
||||
};
|
||||
|
||||
} // namespace deskflow::gui
|
||||
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
#include "base/NetworkProtocol.h"
|
||||
#include "gui/Hotkey.h"
|
||||
#include "gui/config/IServerConfig.h"
|
||||
#include "gui/config/ScreenConfig.h"
|
||||
#include "gui/config/ScreenList.h"
|
||||
|
||||
|
|
@ -31,21 +30,18 @@ const auto kDefaultProtocol = NetworkProtocol::Barrier;
|
|||
|
||||
} // namespace deskflow::gui
|
||||
|
||||
class ServerConfig : public ScreenConfig, public deskflow::gui::IServerConfig
|
||||
class ServerConfig : public ScreenConfig
|
||||
{
|
||||
friend class ServerConfigDialog;
|
||||
friend QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config);
|
||||
|
||||
public:
|
||||
explicit ServerConfig(int columns = kDefaultColumns, int rows = kDefaultRows);
|
||||
~ServerConfig() override = default;
|
||||
~ServerConfig() = default;
|
||||
|
||||
bool operator==(const ServerConfig &sc) const;
|
||||
|
||||
//
|
||||
// Overrides
|
||||
//
|
||||
const ScreenList &screens() const override
|
||||
const ScreenList &screens() const
|
||||
{
|
||||
return m_Screens;
|
||||
}
|
||||
|
|
@ -131,17 +127,10 @@ public:
|
|||
}
|
||||
static size_t defaultClipboardSharingSize();
|
||||
|
||||
//
|
||||
// Overrides
|
||||
//
|
||||
bool save(const QString &fileName) const override;
|
||||
bool screenExists(const QString &screenName) const override;
|
||||
void save(QFile &file) const override;
|
||||
bool isFull() const override;
|
||||
|
||||
//
|
||||
// New methods
|
||||
//
|
||||
bool save(const QString &fileName) const;
|
||||
bool screenExists(const QString &screenName) const;
|
||||
void save(QFile &file) const;
|
||||
bool isFull() const;
|
||||
void commit();
|
||||
int numScreens() const;
|
||||
QString getServerName() const;
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
||||
* SPDX-FileCopyrightText: (C) 2021 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "ClientConnection.h"
|
||||
|
||||
#include "common/Settings.h"
|
||||
|
||||
#include <QHostAddress>
|
||||
|
||||
namespace deskflow::gui {
|
||||
|
||||
void ClientConnection::handleLogLine(const QString &logLine)
|
||||
{
|
||||
if (logLine.contains("disconnected from server")) {
|
||||
m_supressMessage = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (logLine.contains("retry in ") && Settings::value(Settings::Client::DynamicConnectionRetry).toBool()) {
|
||||
auto line = logLine.mid(logLine.indexOf("in ") + 3);
|
||||
int seconds = line.mid(0, line.indexOf(" ")).toInt();
|
||||
Q_EMIT updateTimeoutDelay(seconds);
|
||||
return;
|
||||
}
|
||||
if (logLine.contains("connected to server")) {
|
||||
m_supressMessage = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (logLine.contains("failed to connect to server")) {
|
||||
if (m_supressMessage) {
|
||||
qDebug("message already shown, skipping");
|
||||
return;
|
||||
}
|
||||
// ignore the message if it's about the server refusing by name as
|
||||
// this will trigger the server to show an 'add client' dialog.
|
||||
if (logLine.contains("server refused client with our name")) {
|
||||
qDebug("ignoring client name refused message");
|
||||
return;
|
||||
}
|
||||
showMessage(logLine);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientConnection::showMessage(const QString &logLine)
|
||||
{
|
||||
using enum deskflow::client::ErrorType;
|
||||
|
||||
if (logLine.isEmpty())
|
||||
return;
|
||||
|
||||
const auto address = Settings::value(Settings::Client::RemoteHost).toString();
|
||||
auto error = NoError;
|
||||
|
||||
if (logLine.contains("server already has a connected client with our name")) {
|
||||
error = AlreadyConnected;
|
||||
} else if (QHostAddress a(address); a.isNull()) {
|
||||
qDebug("ip not detected, showing hostname error");
|
||||
error = HostnameError;
|
||||
} else {
|
||||
qDebug("ip detected, showing generic error");
|
||||
error = GenericError;
|
||||
}
|
||||
|
||||
if (error == NoError)
|
||||
return;
|
||||
|
||||
Q_EMIT requestShowError(error, address);
|
||||
}
|
||||
|
||||
} // namespace deskflow::gui
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
||||
* SPDX-FileCopyrightText: (C) 2021 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/Enums.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
|
||||
class QWidget;
|
||||
|
||||
namespace deskflow::gui {
|
||||
|
||||
class ClientConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ClientConnection(QWidget *parent) : m_pParent(parent)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void handleLogLine(const QString &line);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* @brief requestShowError, This signal is emitted when the client
|
||||
* connection would like the owning process to report an error message
|
||||
* @param error the type of error being reported
|
||||
* @param address of the host
|
||||
*/
|
||||
void requestShowError(deskflow::client::ErrorType error, const QString &address);
|
||||
void updateTimeoutDelay(int newTimeout);
|
||||
|
||||
private:
|
||||
void showMessage(const QString &logLine);
|
||||
|
||||
QWidget *m_pParent;
|
||||
bool m_supressMessage = false;
|
||||
};
|
||||
|
||||
} // namespace deskflow::gui
|
||||
|
|
@ -99,7 +99,7 @@ QString CoreProcess::wrapIpv6(const QString &address)
|
|||
// CoreProcess
|
||||
//
|
||||
|
||||
CoreProcess::CoreProcess(const IServerConfig &serverConfig)
|
||||
CoreProcess::CoreProcess(const ServerConfig &serverConfig)
|
||||
: m_serverConfig(serverConfig),
|
||||
m_daemonIpcClient{new ipc::DaemonIpcClient(this)}
|
||||
{
|
||||
|
|
@ -430,7 +430,7 @@ void CoreProcess::stop(std::optional<ProcessMode> processModeOption)
|
|||
|
||||
if (m_coreIpcClient) {
|
||||
m_coreIpcClient->disconnectFromServer();
|
||||
delete m_coreIpcClient;
|
||||
m_coreIpcClient->deleteLater();
|
||||
m_coreIpcClient = nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -548,6 +548,22 @@ void CoreProcess::onCoreIpcMessageReceived(const QString &command, const QString
|
|||
m_secureSocketVersion = args;
|
||||
Q_EMIT securityLevelChanged(args);
|
||||
}
|
||||
} else if (command == "unrecognisedClient") {
|
||||
Q_EMIT unrecognisedClient(args);
|
||||
} else if (command == "connectionRefused") {
|
||||
const auto metaEnum = QMetaEnum::fromType<deskflow::core::ConnectionRefusal>();
|
||||
bool ok = false;
|
||||
const auto reason =
|
||||
static_cast<deskflow::core::ConnectionRefusal>(metaEnum.keyToValue(args.toUtf8().constData(), &ok));
|
||||
if (ok) {
|
||||
Q_EMIT connectionRefused(reason);
|
||||
} else {
|
||||
qWarning("core ipc got unknown connection refusal: %s", args.toUtf8().constData());
|
||||
}
|
||||
} else if (command == "retryIn") {
|
||||
Q_EMIT retryIn(args.toInt());
|
||||
} else if (command == "peerFingerprint") {
|
||||
Q_EMIT peerFingerprint(args);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include "common/Enums.h"
|
||||
#include "common/Settings.h"
|
||||
#include "gui/FileTail.h"
|
||||
#include "gui/config/IServerConfig.h"
|
||||
#include "gui/config/ServerConfig.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QObject>
|
||||
|
|
@ -29,8 +29,6 @@ class CoreProcess : public QObject
|
|||
using ConnectionState = deskflow::core::ConnectionState;
|
||||
using ProcessMode = Settings::ProcessMode;
|
||||
using ProcessState = deskflow::core::ProcessState;
|
||||
using IServerConfig = deskflow::gui::IServerConfig;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
|
@ -40,7 +38,7 @@ public:
|
|||
StartFailed
|
||||
};
|
||||
|
||||
explicit CoreProcess(const IServerConfig &serverConfig);
|
||||
explicit CoreProcess(const ServerConfig &serverConfig);
|
||||
|
||||
void start(std::optional<ProcessMode> processMode = std::nullopt);
|
||||
void stop(std::optional<ProcessMode> processMode = std::nullopt);
|
||||
|
|
@ -91,6 +89,10 @@ Q_SIGNALS:
|
|||
void daemonIpcClientConnectionFailed();
|
||||
void connectedClientsChanged(const QStringList &clients);
|
||||
void securityLevelChanged(QString securityLevel);
|
||||
void unrecognisedClient(const QString &clientName);
|
||||
void connectionRefused(deskflow::core::ConnectionRefusal reason);
|
||||
void retryIn(int seconds);
|
||||
void peerFingerprint(const QString &fingerprint);
|
||||
|
||||
private Q_SLOTS:
|
||||
void onProcessFinished(int exitCode, QProcess::ExitStatus);
|
||||
|
|
@ -116,7 +118,7 @@ private:
|
|||
static QString processStateToString(const CoreProcess::ProcessState state);
|
||||
static QString wrapIpv6(const QString &address);
|
||||
|
||||
const IServerConfig &m_serverConfig;
|
||||
const ServerConfig &m_serverConfig;
|
||||
QString m_address;
|
||||
ProcessState m_processState = ProcessState::Stopped;
|
||||
ConnectionState m_connectionState = ConnectionState::Disconnected;
|
||||
|
|
|
|||
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
||||
* SPDX-FileCopyrightText: (C) 2021 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "ServerConnection.h"
|
||||
|
||||
#include "ServerMessage.h"
|
||||
#include "common/Settings.h"
|
||||
|
||||
#include <QPushButton>
|
||||
|
||||
namespace deskflow::gui {
|
||||
|
||||
ServerConnection::ServerConnection(QWidget *parent, IServerConfig &serverConfig)
|
||||
: m_pParent(parent),
|
||||
m_serverConfig(serverConfig)
|
||||
{
|
||||
}
|
||||
|
||||
void ServerConnection::handleLogLine(const QString &logLine)
|
||||
{
|
||||
ServerMessage message(logLine);
|
||||
const auto &clientName = message.getClientName();
|
||||
|
||||
if (m_ignoredClients.contains(clientName)) {
|
||||
qDebug("ignoring %s:", qPrintable(clientName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.isDisconnectedMessage()) {
|
||||
m_connectedClients.remove(clientName);
|
||||
Q_EMIT clientsChanged(connectedClients());
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.isConnectedMessage()) {
|
||||
m_connectedClients.insert(clientName);
|
||||
Q_EMIT clientsChanged(connectedClients());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!message.isNewClientMessage()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_messageShowing) {
|
||||
qDebug("new client message already shown, skipping for now");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_serverConfigDialogVisible) {
|
||||
qDebug("server config dialog visible, skipping new client prompt");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Settings::value(Settings::Server::ExternalConfig).toBool()) {
|
||||
qDebug("external config enabled, skipping new client prompt");
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_connectedClients.contains(clientName)) {
|
||||
qDebug("already got request, skipping new client prompt for: %s", qPrintable(clientName));
|
||||
return;
|
||||
}
|
||||
|
||||
handleNewClient(clientName);
|
||||
}
|
||||
|
||||
void ServerConnection::handleNewClient(const QString &clientName)
|
||||
{
|
||||
if (m_serverConfig.isFull()) {
|
||||
qDebug("server config full, skipping new client prompt for: %s", qPrintable(clientName));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_serverConfig.screenExists(clientName)) {
|
||||
qDebug("client already added, skipping new client prompt for: %s", qPrintable(clientName));
|
||||
return;
|
||||
}
|
||||
|
||||
m_messageShowing = true;
|
||||
Q_EMIT requestNewClientPrompt(clientName);
|
||||
}
|
||||
|
||||
void ServerConnection::handleNewClientResult(const QString &clientName, bool acceptClient)
|
||||
{
|
||||
m_messageShowing = false;
|
||||
if (!acceptClient) {
|
||||
qDebug("declined dialog, ignoring client: %s", qPrintable(clientName));
|
||||
m_ignoredClients.insert(clientName);
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug("accepted dialog, adding client: %s", qPrintable(clientName));
|
||||
Q_EMIT configureClient(clientName);
|
||||
m_connectedClients.insert(clientName);
|
||||
Q_EMIT clientsChanged(connectedClients());
|
||||
}
|
||||
|
||||
QStringList ServerConnection::connectedClients() const
|
||||
{
|
||||
return QStringList(m_connectedClients.begin(), m_connectedClients.end());
|
||||
}
|
||||
|
||||
} // namespace deskflow::gui
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
||||
* SPDX-FileCopyrightText: (C) 2021 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "gui/Messages.h"
|
||||
#include "gui/config/IServerConfig.h"
|
||||
|
||||
namespace deskflow::gui {
|
||||
|
||||
class ServerConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
using IServerConfig = deskflow::gui::IServerConfig;
|
||||
|
||||
public:
|
||||
explicit ServerConnection(QWidget *parent, IServerConfig &serverConfig);
|
||||
void handleLogLine(const QString &logLine);
|
||||
void serverConfigDialogVisible(bool visible)
|
||||
{
|
||||
m_serverConfigDialogVisible = visible;
|
||||
}
|
||||
|
||||
QStringList connectedClients() const;
|
||||
void handleNewClientResult(const QString &clientName, bool acceptClient);
|
||||
|
||||
Q_SIGNALS:
|
||||
void requestNewClientPrompt(const QString &clientName);
|
||||
void configureClient(const QString &clientName);
|
||||
void clientsChanged(const QStringList &clients);
|
||||
|
||||
private:
|
||||
void handleNewClient(const QString &clientName);
|
||||
|
||||
QWidget *m_pParent;
|
||||
IServerConfig &m_serverConfig;
|
||||
QSet<QString> m_connectedClients;
|
||||
QSet<QString> m_ignoredClients;
|
||||
bool m_messageShowing = false;
|
||||
bool m_serverConfigDialogVisible = false;
|
||||
};
|
||||
|
||||
} // namespace deskflow::gui
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2021 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "ServerMessage.h"
|
||||
|
||||
namespace deskflow::gui {
|
||||
|
||||
ServerMessage::ServerMessage(const QString &message) : m_message(message), m_clientName(parseClientName(message))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
bool ServerMessage::isNewClientMessage() const
|
||||
{
|
||||
return m_message.contains("unrecognised client name");
|
||||
}
|
||||
|
||||
bool ServerMessage::isExitMessage() const
|
||||
{
|
||||
return m_message.contains("process exited");
|
||||
}
|
||||
|
||||
bool ServerMessage::isConnectedMessage() const
|
||||
{
|
||||
return m_message.contains("has connected");
|
||||
}
|
||||
|
||||
bool ServerMessage::isDisconnectedMessage() const
|
||||
{
|
||||
return m_message.contains("has disconnected");
|
||||
}
|
||||
|
||||
const QString &ServerMessage::getClientName() const
|
||||
{
|
||||
return m_clientName;
|
||||
}
|
||||
|
||||
QString ServerMessage::parseClientName(const QString &line) const
|
||||
{
|
||||
QString clientName("Unknown");
|
||||
|
||||
auto nameStart = line.indexOf('"') + 1;
|
||||
|
||||
if (auto nameEnd = line.indexOf('"', nameStart); nameEnd > nameStart) {
|
||||
clientName = line.mid(nameStart, nameEnd - nameStart);
|
||||
}
|
||||
|
||||
return clientName;
|
||||
}
|
||||
|
||||
} // namespace deskflow::gui
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2021 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace deskflow::gui {
|
||||
|
||||
class ServerMessage
|
||||
{
|
||||
QString m_message;
|
||||
QString m_clientName;
|
||||
|
||||
public:
|
||||
explicit ServerMessage(const QString &message);
|
||||
|
||||
bool isNewClientMessage() const;
|
||||
bool isExitMessage() const;
|
||||
bool isConnectedMessage() const;
|
||||
bool isDisconnectedMessage() const;
|
||||
|
||||
const QString &getClientName() const;
|
||||
|
||||
private:
|
||||
QString parseClientName(const QString &line) const;
|
||||
};
|
||||
|
||||
} // namespace deskflow::gui
|
||||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
using namespace deskflow::gui;
|
||||
|
||||
SettingsDialog::SettingsDialog(QWidget *parent, const IServerConfig &serverConfig)
|
||||
SettingsDialog::SettingsDialog(QWidget *parent, const ServerConfig &serverConfig)
|
||||
: QDialog(parent),
|
||||
ui{std::make_unique<Ui::SettingsDialog>()},
|
||||
m_serverConfig(serverConfig)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
#pragma once
|
||||
#include <QDialog>
|
||||
|
||||
#include "gui/config/IServerConfig.h"
|
||||
#include "gui/config/ServerConfig.h"
|
||||
|
||||
namespace Ui {
|
||||
class SettingsDialog;
|
||||
|
|
@ -17,13 +17,11 @@ class SettingsDialog;
|
|||
|
||||
class SettingsDialog : public QDialog
|
||||
{
|
||||
using IServerConfig = deskflow::gui::IServerConfig;
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void extracted();
|
||||
SettingsDialog(QWidget *parent, const IServerConfig &serverConfig);
|
||||
SettingsDialog(QWidget *parent, const ServerConfig &serverConfig);
|
||||
~SettingsDialog() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
|
|
@ -86,5 +84,5 @@ private:
|
|||
|
||||
bool m_interfaceSetOnLoad = false;
|
||||
std::unique_ptr<Ui::SettingsDialog> ui;
|
||||
const IServerConfig &m_serverConfig;
|
||||
const ServerConfig &m_serverConfig;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,15 +6,14 @@
|
|||
|
||||
#include "IpcClient.h"
|
||||
|
||||
#include "common/VersionInfo.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QLocalSocket>
|
||||
#include <QTimer>
|
||||
|
||||
namespace deskflow::gui::ipc {
|
||||
|
||||
const auto kTimeout = 1000;
|
||||
const auto kRetryLimit = 3;
|
||||
|
||||
IpcClient::IpcClient(QObject *parent, const QString &socketName)
|
||||
: QObject(parent),
|
||||
m_socket{new QLocalSocket(this)},
|
||||
|
|
@ -48,6 +47,8 @@ void IpcClient::connectToServer()
|
|||
|
||||
void IpcClient::attemptConnection()
|
||||
{
|
||||
const auto kRetryLimit = 3;
|
||||
|
||||
if (m_retryCount >= kRetryLimit) {
|
||||
qWarning() << "ipc client failed to connect after" << kRetryLimit << "attempts";
|
||||
m_state = State::Unconnected;
|
||||
|
|
@ -67,8 +68,9 @@ void IpcClient::attemptConnection()
|
|||
connect(
|
||||
m_socket, &QLocalSocket::connected, this,
|
||||
[this] {
|
||||
m_socket->write("hello\n");
|
||||
qDebug() << "ipc client sent hello";
|
||||
const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha);
|
||||
m_socket->write(QString("hello=%1\n").arg(versionId).toUtf8());
|
||||
qDebug() << "ipc client sent hello with version:" << versionId;
|
||||
},
|
||||
Qt::SingleShotConnection
|
||||
);
|
||||
|
|
@ -141,10 +143,8 @@ void IpcClient::handleReadyRead()
|
|||
continue;
|
||||
}
|
||||
|
||||
if (m_state == State::Connecting && parts.at(0) == "hello") {
|
||||
m_state = State::Connected;
|
||||
qDebug() << "ipc client connected";
|
||||
Q_EMIT connected();
|
||||
if (m_state == State::Connecting) {
|
||||
handleHandshakeMessage(parts);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -156,6 +156,26 @@ void IpcClient::handleReadyRead()
|
|||
}
|
||||
}
|
||||
|
||||
void IpcClient::handleHandshakeMessage(const QStringList &parts)
|
||||
{
|
||||
if (parts.at(0) != "hello") {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha);
|
||||
const auto serverVersion = parts.size() >= 2 ? parts.at(1) : QString();
|
||||
if (serverVersion != versionId) {
|
||||
qCritical() << "ipc version mismatch (client:" << versionId << "server:" << serverVersion << ")";
|
||||
disconnectFromServer();
|
||||
Q_EMIT connectionFailed();
|
||||
return;
|
||||
}
|
||||
|
||||
m_state = State::Connected;
|
||||
qDebug() << "ipc client connected";
|
||||
Q_EMIT connected();
|
||||
}
|
||||
|
||||
void IpcClient::sendMessage(const QString &message)
|
||||
{
|
||||
if (m_state != State::Connected) {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ protected:
|
|||
|
||||
private:
|
||||
void attemptConnection();
|
||||
void handleHandshakeMessage(const QStringList &parts);
|
||||
|
||||
QLocalSocket *m_socket;
|
||||
State m_state{State::Unconnected};
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
#include "base/IEventQueue.h"
|
||||
#include "base/Log.h"
|
||||
#include "deskflow/AppUtil.h"
|
||||
#include "deskflow/ipc/CoreIpc.h"
|
||||
#include "deskflow/DeskflowException.h"
|
||||
#include "deskflow/IPlatformScreen.h"
|
||||
#include "deskflow/OptionTypes.h"
|
||||
|
|
@ -19,6 +18,7 @@
|
|||
#include "deskflow/ProtocolTypes.h"
|
||||
#include "deskflow/Screen.h"
|
||||
#include "deskflow/StreamChunker.h"
|
||||
#include "deskflow/ipc/CoreIpc.h"
|
||||
#include "net/TCPSocket.h"
|
||||
#include "server/ClientListener.h"
|
||||
#include "server/ClientProxy.h"
|
||||
|
|
@ -235,6 +235,7 @@ void Server::adoptClient(BaseClientProxy *client)
|
|||
// name must be in our configuration
|
||||
if (!m_config->isScreen(client->getName())) {
|
||||
LOG_WARN("unrecognised client name \"%s\", check server config", client->getName().c_str());
|
||||
ipcSendToClient("unrecognisedClient", QString::fromStdString(client->getName()));
|
||||
closeClient(client, kMsgEUnknown);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,25 +1,9 @@
|
|||
# SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
create_test(
|
||||
NAME ClientConnectionTests
|
||||
DEPENDS gui
|
||||
SOURCE ClientConnectionTests.cpp
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/gui"
|
||||
)
|
||||
|
||||
create_test(
|
||||
NAME ServerConnectionTests
|
||||
DEPENDS gui
|
||||
SOURCE ServerConnectionTests.cpp
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/gui"
|
||||
)
|
||||
|
||||
|
||||
create_test(
|
||||
NAME NetworkMonitorTests
|
||||
DEPENDS gui
|
||||
SOURCE NetworkMonitorTests.cpp
|
||||
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/gui"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,130 +0,0 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
|
||||
* SPDX-FileCopyrightText: (C) 2024 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "ClientConnectionTests.h"
|
||||
|
||||
#include "gui/core/ClientConnection.h"
|
||||
#include <common/Settings.h>
|
||||
|
||||
#include <QSignalSpy>
|
||||
|
||||
using namespace deskflow::gui;
|
||||
|
||||
void ClientConnectionTests::initTestCase()
|
||||
{
|
||||
QDir dir;
|
||||
QVERIFY(dir.mkpath(m_settingsPath));
|
||||
|
||||
QFile oldSettings(m_settingsFile);
|
||||
if (oldSettings.exists())
|
||||
oldSettings.remove();
|
||||
|
||||
Settings::setSettingsFile(m_settingsFile);
|
||||
Settings::setStateFile(m_stateFile);
|
||||
}
|
||||
|
||||
void ClientConnectionTests::handleLogLine_alreadyConnected_showError()
|
||||
{
|
||||
ClientConnection clientConnection(nullptr);
|
||||
const auto serverName = QStringLiteral("test server");
|
||||
Settings::setValue(Settings::Client::RemoteHost, serverName);
|
||||
|
||||
QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
clientConnection.handleLogLine(
|
||||
"failed to connect to server\n"
|
||||
"server already has a connected client with our name"
|
||||
);
|
||||
|
||||
QCOMPARE(spy.count(), 1);
|
||||
}
|
||||
|
||||
void ClientConnectionTests::handleLogLine_withHostname_showError()
|
||||
{
|
||||
ClientConnection clientConnection(nullptr);
|
||||
const auto serverName = QStringLiteral("test server");
|
||||
Settings::setValue(Settings::Client::RemoteHost, serverName);
|
||||
|
||||
QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
clientConnection.handleLogLine("failed to connect to server");
|
||||
|
||||
QCOMPARE(spy.count(), 1);
|
||||
}
|
||||
|
||||
void ClientConnectionTests::handleLogLine_withIpAddress_showError()
|
||||
{
|
||||
ClientConnection clientConnection(nullptr);
|
||||
const auto serverName = QStringLiteral("1.1.1.1");
|
||||
Settings::setValue(Settings::Client::RemoteHost, serverName);
|
||||
|
||||
QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
clientConnection.handleLogLine("failed to connect to server");
|
||||
|
||||
QCOMPARE(spy.count(), 1);
|
||||
}
|
||||
|
||||
void ClientConnectionTests::handleLogLine_serverRefusedClient_shouldNotShowError()
|
||||
{
|
||||
ClientConnection clientConnection(nullptr);
|
||||
|
||||
QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
clientConnection.handleLogLine(
|
||||
"failed to connect to server\n"
|
||||
"server refused client with our name"
|
||||
);
|
||||
|
||||
QCOMPARE(spy.count(), 0);
|
||||
}
|
||||
|
||||
void ClientConnectionTests::handleLogLine_connected_shouldPreventFutureError()
|
||||
{
|
||||
ClientConnection clientConnection(nullptr);
|
||||
clientConnection.handleLogLine("connected to server");
|
||||
|
||||
QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
clientConnection.handleLogLine("failed to connect to server");
|
||||
|
||||
QCOMPARE(spy.count(), 0);
|
||||
}
|
||||
|
||||
void ClientConnectionTests::handleLogLine_connectToggled_showAfterDisconnect()
|
||||
{
|
||||
ClientConnection clientConnection(nullptr);
|
||||
clientConnection.handleLogLine("connected to server");
|
||||
|
||||
QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
clientConnection.handleLogLine("failed to connect to server");
|
||||
clientConnection.handleLogLine("disconnected from server");
|
||||
clientConnection.handleLogLine("failed to connect to server");
|
||||
|
||||
QCOMPARE(spy.count(), 1);
|
||||
}
|
||||
|
||||
void ClientConnectionTests::handleLogLine_otherMessage_shouldNotShowError()
|
||||
{
|
||||
ClientConnection clientConnection(nullptr);
|
||||
|
||||
QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
clientConnection.handleLogLine("hello world");
|
||||
|
||||
QCOMPARE(spy.count(), 0);
|
||||
}
|
||||
|
||||
QTEST_MAIN(ClientConnectionTests)
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include <QTest>
|
||||
|
||||
class ClientConnectionTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private Q_SLOTS:
|
||||
// Test are run in order top to bottom
|
||||
void initTestCase();
|
||||
void handleLogLine_alreadyConnected_showError();
|
||||
void handleLogLine_withHostname_showError();
|
||||
void handleLogLine_withIpAddress_showError();
|
||||
void handleLogLine_serverRefusedClient_shouldNotShowError();
|
||||
void handleLogLine_connected_shouldPreventFutureError();
|
||||
void handleLogLine_connectToggled_showAfterDisconnect();
|
||||
void handleLogLine_otherMessage_shouldNotShowError();
|
||||
|
||||
private:
|
||||
inline static const QString m_settingsPath = QStringLiteral("tmp/test");
|
||||
inline static const QString m_settingsFile = QStringLiteral("%1/Deskflow.conf").arg(m_settingsPath);
|
||||
inline static const QString m_stateFile = QStringLiteral("%1/Deskflow.state").arg(m_settingsPath);
|
||||
};
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
|
||||
* SPDX-FileCopyrightText: (C) 2024 Symless Ltd.
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include "ServerConnectionTests.h"
|
||||
|
||||
#include "gui/config/ServerConfig.h"
|
||||
#include "gui/core/ServerConnection.h"
|
||||
#include <common/Settings.h>
|
||||
|
||||
#include <QSignalSpy>
|
||||
|
||||
using namespace deskflow::gui;
|
||||
|
||||
class FullServerConfig : public ServerConfig
|
||||
{
|
||||
public:
|
||||
bool isFull() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class ScreenExistsServerConfig : public ServerConfig
|
||||
{
|
||||
public:
|
||||
bool screenExists(const QString &screenName) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
void ServerConnectionTests::initTestCase()
|
||||
{
|
||||
QDir dir;
|
||||
QVERIFY(dir.mkpath(m_settingsPath));
|
||||
|
||||
QFile oldSettings(m_settingsFile);
|
||||
if (oldSettings.exists())
|
||||
oldSettings.remove();
|
||||
|
||||
Settings::setSettingsFile(m_settingsFile);
|
||||
Settings::setStateFile(m_stateFile);
|
||||
}
|
||||
|
||||
void ServerConnectionTests::handleLogLine_newClient_shouldShowPrompt()
|
||||
{
|
||||
ServerConfig m_serverConfig;
|
||||
ServerConnection serverConnection(nullptr, m_serverConfig);
|
||||
|
||||
QString clientName = "test client";
|
||||
|
||||
QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
|
||||
QCOMPARE(spy.count(), 1);
|
||||
}
|
||||
|
||||
void ServerConnectionTests::handleLogLine_ignoredClient_shouldNotShowPrompt()
|
||||
{
|
||||
ServerConfig m_serverConfig;
|
||||
ServerConnection serverConnection(nullptr, m_serverConfig);
|
||||
QString clientName = "test client";
|
||||
serverConnection.handleNewClientResult(clientName, false);
|
||||
|
||||
QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
|
||||
QCOMPARE(spy.count(), 0);
|
||||
}
|
||||
|
||||
void ServerConnectionTests::handleLogLine_serverConfigFull_shouldNotShowPrompt()
|
||||
{
|
||||
FullServerConfig m_serverConfig;
|
||||
ServerConnection serverConnection(nullptr, m_serverConfig);
|
||||
|
||||
QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
|
||||
QCOMPARE(spy.count(), 0);
|
||||
}
|
||||
|
||||
void ServerConnectionTests::handleLogLine_screenExists_shouldNotShowPrompt()
|
||||
{
|
||||
ScreenExistsServerConfig m_serverConfig;
|
||||
ServerConnection serverConnection(nullptr, m_serverConfig);
|
||||
|
||||
QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt);
|
||||
QVERIFY(spy.isValid());
|
||||
|
||||
serverConnection.handleLogLine(R"(unrecognised client name "test client")");
|
||||
QCOMPARE(spy.count(), 0);
|
||||
}
|
||||
|
||||
QTEST_MAIN(ServerConnectionTests)
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello <sithlord48@gmail.com>
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
||||
#include <QTest>
|
||||
|
||||
class ServerConnectionTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private Q_SLOTS:
|
||||
// Test are run in order top to bottom
|
||||
void initTestCase();
|
||||
void handleLogLine_newClient_shouldShowPrompt();
|
||||
void handleLogLine_ignoredClient_shouldNotShowPrompt();
|
||||
void handleLogLine_serverConfigFull_shouldNotShowPrompt();
|
||||
void handleLogLine_screenExists_shouldNotShowPrompt();
|
||||
|
||||
private:
|
||||
inline static const QString m_settingsPath = QStringLiteral("tmp/test");
|
||||
inline static const QString m_settingsFile = QStringLiteral("%1/Deskflow.conf").arg(m_settingsPath);
|
||||
inline static const QString m_stateFile = QStringLiteral("%1/Deskflow.state").arg(m_settingsPath);
|
||||
};
|
||||
Loading…
Reference in a new issue