refactor: remove legacy deps pattern and hello back class
This commit is contained in:
parent
6459eb40df
commit
be2546c27b
6 changed files with 29 additions and 422 deletions
|
|
@ -6,8 +6,6 @@
|
|||
add_library(client STATIC
|
||||
Client.cpp
|
||||
Client.h
|
||||
HelloBack.cpp
|
||||
HelloBack.h
|
||||
ServerProxy.cpp
|
||||
ServerProxy.h
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016, 2026 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
|
@ -14,9 +14,9 @@
|
|||
#include "client/ServerProxy.h"
|
||||
#include "common/Settings.h"
|
||||
#include "deskflow/Clipboard.h"
|
||||
#include "deskflow/DeskflowException.h"
|
||||
#include "deskflow/IPlatformScreen.h"
|
||||
#include "deskflow/PacketStreamFilter.h"
|
||||
#include "deskflow/ProtocolTypes.h"
|
||||
#include "deskflow/ProtocolUtil.h"
|
||||
#include "deskflow/Screen.h"
|
||||
#include "deskflow/StreamChunker.h"
|
||||
|
|
@ -27,9 +27,6 @@
|
|||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
using namespace deskflow::client;
|
||||
|
||||
//
|
||||
// Client
|
||||
|
|
@ -52,19 +49,6 @@ Client::Client(
|
|||
// register suspend/resume event handlers
|
||||
m_events->addHandler(EventTypes::ScreenSuspend, getEventTarget(), [this](const auto &) { handleSuspend(); });
|
||||
m_events->addHandler(EventTypes::ScreenResume, getEventTarget(), [this](const auto &) { handleResume(); });
|
||||
|
||||
m_pHelloBack = std::make_unique<HelloBack>(std::make_shared<HelloBack::Deps>(
|
||||
[this]() {
|
||||
sendConnectionFailedEvent("got invalid hello message from server");
|
||||
cleanupTimer();
|
||||
cleanupConnection();
|
||||
},
|
||||
[this](int major, int minor) {
|
||||
sendConnectionFailedEvent(IncompatibleClientException(major, minor).what());
|
||||
cleanupTimer();
|
||||
cleanupConnection();
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
Client::~Client()
|
||||
|
|
@ -584,7 +568,32 @@ void Client::handleClipboardGrabbed(const Event &event)
|
|||
|
||||
void Client::handleHello()
|
||||
{
|
||||
m_pHelloBack->handleHello(m_stream, m_name);
|
||||
int16_t serverMajor;
|
||||
int16_t serverMinor;
|
||||
|
||||
// as luck would have it, both "Synergy" and "Barrier" are 7 chars,
|
||||
// so we eat 7 chars and then test for either protocol name.
|
||||
// we cannot re-use `readf` to check for various hello messages,
|
||||
// as `readf` eats bytes (advances the stream position reference).
|
||||
std::string protocolName;
|
||||
ProtocolUtil::readf(m_stream, kMsgHello, &protocolName, &serverMajor, &serverMinor);
|
||||
|
||||
if (protocolName != kSynergyProtocolName && protocolName != kBarrierProtocolName) {
|
||||
LOG_WARN("hello back received with protocol: '%s'", protocolName.c_str());
|
||||
sendConnectionFailedEvent("got invalid hello message from server");
|
||||
cleanupTimer();
|
||||
cleanupConnection();
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG(
|
||||
"saying hello back with version %s %d.%d", protocolName.c_str(), kProtocolMajorVersion, kProtocolMinorVersion
|
||||
);
|
||||
|
||||
// dynamically build write format for hello back since `ProtocolUtil::writef`
|
||||
// doesn't support formatting fixed length strings yet.
|
||||
std::string helloBackMessage = protocolName + kMsgHelloBackArgs;
|
||||
ProtocolUtil::writef(m_stream, helloBackMessage.c_str(), kProtocolMajorVersion, kProtocolMinorVersion, &m_name);
|
||||
|
||||
// now connected but waiting to complete handshake
|
||||
setupScreen();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* Deskflow -- mouse and keyboard sharing utility
|
||||
* SPDX-FileCopyrightText: (C) 2025 Deskflow Developers
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2012 - 2016, 2026 Symless Ltd.
|
||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||
*/
|
||||
|
|
@ -10,13 +10,11 @@
|
|||
|
||||
#include "deskflow/IClient.h"
|
||||
|
||||
#include "HelloBack.h"
|
||||
#include "base/EventTypes.h"
|
||||
#include "deskflow/IClipboard.h"
|
||||
#include "net/NetworkAddress.h"
|
||||
|
||||
#include <climits>
|
||||
#include <memory>
|
||||
|
||||
class Event;
|
||||
class EventQueueTimer;
|
||||
|
|
@ -203,5 +201,4 @@ private:
|
|||
bool m_enableClipboard = true;
|
||||
size_t m_maximumClipboardSize = INT_MAX;
|
||||
size_t m_resolvedAddressesCount = 0;
|
||||
std::unique_ptr<deskflow::client::HelloBack> m_pHelloBack;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,99 +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
|
||||
*/
|
||||
|
||||
#include "HelloBack.h"
|
||||
|
||||
#include "base/Log.h"
|
||||
#include "deskflow/ProtocolTypes.h"
|
||||
#include "deskflow/ProtocolUtil.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace deskflow::client {
|
||||
|
||||
//
|
||||
// HelloBack::Deps
|
||||
//
|
||||
|
||||
void HelloBack::Deps::invalidHello()
|
||||
{
|
||||
m_invalidHello();
|
||||
}
|
||||
|
||||
void HelloBack::Deps::incompatible(int major, int minor)
|
||||
{
|
||||
m_incompatible(major, minor);
|
||||
}
|
||||
|
||||
//
|
||||
// HelloBack
|
||||
//
|
||||
|
||||
void HelloBack::handleHello(deskflow::IStream *stream, const std::string &clientName) const
|
||||
{
|
||||
int16_t serverMajor;
|
||||
int16_t serverMinor;
|
||||
|
||||
// as luck would have it, both "Synergy" and "Barrier" are 7 chars,
|
||||
// so we eat 7 chars and then test for either protocol name.
|
||||
// we cannot re-use `readf` to check for various hello messages,
|
||||
// as `readf` eats bytes (advances the stream position reference).
|
||||
std::string protocolName;
|
||||
ProtocolUtil::readf(stream, kMsgHello, &protocolName, &serverMajor, &serverMinor);
|
||||
|
||||
if (protocolName != kSynergyProtocolName && protocolName != kBarrierProtocolName) {
|
||||
m_deps->invalidHello();
|
||||
return;
|
||||
}
|
||||
|
||||
// check versions
|
||||
LOG_DEBUG("got hello from %s, protocol v%d.%d", protocolName.c_str(), serverMajor, serverMinor);
|
||||
|
||||
const auto helloBackMajor = m_majorVersion;
|
||||
auto helloBackMinor = m_minorVersion;
|
||||
|
||||
if (shouldDowngrade(serverMajor, serverMinor)) {
|
||||
LOG_NOTE("downgrading to %d.%d protocol for server", serverMajor, serverMinor);
|
||||
helloBackMinor = serverMinor;
|
||||
} else if (serverMajor < m_majorVersion || (serverMajor == m_majorVersion && serverMinor < m_minorVersion)) {
|
||||
m_deps->incompatible(serverMajor, serverMinor);
|
||||
return;
|
||||
}
|
||||
|
||||
// say hello back with same protocol name and version
|
||||
LOG_DEBUG("saying hello back with version %s %d.%d", protocolName.c_str(), helloBackMajor, helloBackMinor);
|
||||
|
||||
// dynamically build write format for hello back since `ProtocolUtil::writef`
|
||||
// doesn't support formatting fixed length strings yet.
|
||||
std::string helloBackMessage = protocolName + kMsgHelloBackArgs;
|
||||
ProtocolUtil::writef(stream, helloBackMessage.c_str(), helloBackMajor, helloBackMinor, &clientName);
|
||||
}
|
||||
|
||||
bool HelloBack::shouldDowngrade(int major, int minor) const
|
||||
{
|
||||
const std::map<int, std::set<int>> map{
|
||||
// 1.6 is compatible with 1.7 and 1.8
|
||||
{6, {7, 8}},
|
||||
|
||||
// 1.7 is compatible with 1.8
|
||||
{7, {8}},
|
||||
};
|
||||
|
||||
if (major == m_majorVersion) {
|
||||
auto versions = map.find(minor);
|
||||
if (versions != map.end()) {
|
||||
auto compatibleVersions = versions->second;
|
||||
if (compatibleVersions.contains(m_minorVersion)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace deskflow::client
|
||||
|
|
@ -1,71 +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 "deskflow/ProtocolTypes.h"
|
||||
#include "io/IStream.h"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string> //IWYU
|
||||
|
||||
namespace deskflow::client {
|
||||
|
||||
class HelloBack
|
||||
{
|
||||
public:
|
||||
struct Deps
|
||||
{
|
||||
Deps() = default;
|
||||
explicit Deps(std::function<void()> invalidHello, std::function<void(int, int)> incompatible)
|
||||
: m_invalidHello(std::move(invalidHello)),
|
||||
m_incompatible(std::move(incompatible))
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
virtual ~Deps() = default;
|
||||
|
||||
/**
|
||||
* @brief Call when invalid hello message received from server.
|
||||
*/
|
||||
virtual void invalidHello();
|
||||
|
||||
/**
|
||||
* @brief Call when the client is incompatible with the server.
|
||||
*/
|
||||
virtual void incompatible(int major, int minor);
|
||||
|
||||
private:
|
||||
std::function<void()> m_invalidHello;
|
||||
std::function<void(int, int)> m_incompatible;
|
||||
};
|
||||
|
||||
explicit HelloBack(
|
||||
std::shared_ptr<Deps> deps, const int16_t majorVersion = kProtocolMajorVersion,
|
||||
const int16_t minorVersion = kProtocolMinorVersion
|
||||
)
|
||||
: m_deps(deps),
|
||||
m_majorVersion(majorVersion),
|
||||
m_minorVersion(minorVersion)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Handle hello message from server and reply with hello back.
|
||||
*/
|
||||
void handleHello(deskflow::IStream *stream, const std::string &clientName) const;
|
||||
|
||||
private:
|
||||
bool shouldDowngrade(int major, int minor) const;
|
||||
|
||||
std::shared_ptr<Deps> m_deps;
|
||||
int16_t m_majorVersion;
|
||||
int16_t m_minorVersion;
|
||||
};
|
||||
|
||||
} // namespace deskflow::client
|
||||
|
|
@ -1,227 +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
|
||||
*/
|
||||
|
||||
#include "client/HelloBack.h"
|
||||
|
||||
#include "unittests/legacytests/mock/io/MockStream.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
using HelloBack = deskflow::client::HelloBack;
|
||||
using namespace testing;
|
||||
|
||||
namespace {
|
||||
|
||||
class MockDeps : public HelloBack::Deps
|
||||
{
|
||||
public:
|
||||
~MockDeps() override = default;
|
||||
MOCK_METHOD(void, invalidHello, (), (override));
|
||||
MOCK_METHOD(void, incompatible, (int major, int minor), (override));
|
||||
};
|
||||
|
||||
void intTo2ByteBuf(int16_t value, std::array<char, 2> &buf)
|
||||
{
|
||||
buf[0] = static_cast<char>((value >> 8) & 0xFF); // MSB
|
||||
buf[1] = static_cast<char>(value & 0xFF); // LSB
|
||||
}
|
||||
|
||||
void intTo4ByteBuf(int32_t value, std::array<char, 4> &buf)
|
||||
{
|
||||
buf[0] = static_cast<char>((value >> 24) & 0xFF); // MSB
|
||||
buf[1] = static_cast<char>((value >> 16) & 0xFF);
|
||||
buf[2] = static_cast<char>((value >> 8) & 0xFF);
|
||||
buf[3] = static_cast<char>(value & 0xFF); // LSB
|
||||
}
|
||||
|
||||
std::string printAsHex(const char *buffer, size_t size)
|
||||
{
|
||||
std::ostringstream hexStream;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
hexStream << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< static_cast<int>(static_cast<unsigned char>(buffer[i])) << " ";
|
||||
}
|
||||
return hexStream.str();
|
||||
}
|
||||
|
||||
void setupMockHelloRead(
|
||||
MockStream &stream, const std::string &protocolName, const int16_t majorVersion, const int16_t minorVersion
|
||||
)
|
||||
{
|
||||
|
||||
std::array<char, 2> majorBuf;
|
||||
std::array<char, 2> minorBuf;
|
||||
intTo2ByteBuf(majorVersion, majorBuf);
|
||||
intTo2ByteBuf(minorVersion, minorBuf);
|
||||
|
||||
EXPECT_CALL(stream, read(_, _))
|
||||
.WillOnce(DoAll(
|
||||
WithArg<0>([protocolName](void *vbuffer) {
|
||||
auto buffer = static_cast<char *>(vbuffer);
|
||||
std::copy(protocolName.begin(), protocolName.end(), buffer);
|
||||
}),
|
||||
Return(7)
|
||||
))
|
||||
.WillOnce(DoAll(
|
||||
WithArg<0>([majorBuf](void *vbuffer) {
|
||||
auto buffer = static_cast<char *>(vbuffer);
|
||||
std::memcpy(buffer, majorBuf.data(), majorBuf.size());
|
||||
}),
|
||||
Return(2)
|
||||
))
|
||||
.WillOnce(DoAll(
|
||||
WithArg<0>([minorBuf](void *vbuffer) {
|
||||
auto buffer = static_cast<char *>(vbuffer);
|
||||
std::memcpy(buffer, minorBuf.data(), minorBuf.size());
|
||||
}),
|
||||
Return(2)
|
||||
));
|
||||
}
|
||||
|
||||
void setupMockHelloBackWrite(
|
||||
MockStream &stream, const std::string &protocolName, const int16_t majorVersion, const int16_t minorVersion,
|
||||
const std::string &name
|
||||
)
|
||||
{
|
||||
|
||||
std::array<char, 2> majorBuf;
|
||||
std::array<char, 2> minorBuf;
|
||||
std::array<char, 4> nameLenBuf;
|
||||
intTo2ByteBuf(majorVersion, majorBuf);
|
||||
intTo2ByteBuf(minorVersion, minorBuf);
|
||||
intTo4ByteBuf(static_cast<int32_t>(name.size()), nameLenBuf);
|
||||
|
||||
const auto versionIntSize = 4;
|
||||
const auto clientNameIntSize = 4;
|
||||
const uint32_t helloBackSize =
|
||||
static_cast<uint32_t>(protocolName.size() + versionIntSize + clientNameIntSize + name.size());
|
||||
|
||||
std::vector<char> expect;
|
||||
expect.reserve(helloBackSize);
|
||||
expect.insert(expect.end(), protocolName.begin(), protocolName.end());
|
||||
expect.insert(expect.end(), majorBuf.begin(), majorBuf.end());
|
||||
expect.insert(expect.end(), minorBuf.begin(), minorBuf.end());
|
||||
expect.insert(expect.end(), nameLenBuf.begin(), nameLenBuf.end());
|
||||
expect.insert(expect.end(), name.begin(), name.end());
|
||||
|
||||
EXPECT_CALL(stream, write(_, helloBackSize)).WillOnce(WithArg<0>([expect, helloBackSize](const void *vbuffer) {
|
||||
const auto buffer = static_cast<const char *>(vbuffer);
|
||||
|
||||
EXPECT_TRUE(std::memcmp(expect.data(), buffer, helloBackSize) == 0)
|
||||
<< "Buffer mismatch\n"
|
||||
<< "Expected: " << printAsHex(expect.data(), helloBackSize) << "\n"
|
||||
<< "Actual: " << printAsHex(buffer, helloBackSize) << "\n";
|
||||
}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(HelloBackTests, handleHello_nastyProtocol_invalidHello)
|
||||
{
|
||||
auto deps = std::make_shared<NiceMock<MockDeps>>();
|
||||
HelloBack helloBack(deps);
|
||||
NiceMock<MockStream> stream;
|
||||
const std::string clientName = "stub";
|
||||
|
||||
setupMockHelloRead(stream, "ShareMouse", 0, 0);
|
||||
|
||||
EXPECT_CALL(*deps, invalidHello()).Times(1);
|
||||
|
||||
helloBack.handleHello(&stream, clientName);
|
||||
}
|
||||
|
||||
TEST(HelloBackTests, handleHello_synergyProtocolCurrent_validMessage)
|
||||
{
|
||||
auto deps = std::make_shared<NiceMock<MockDeps>>();
|
||||
HelloBack helloBack(deps, 1, 2);
|
||||
NiceMock<MockStream> stream;
|
||||
const std::string clientName = "stub";
|
||||
|
||||
setupMockHelloRead(stream, "Synergy", 1, 2);
|
||||
|
||||
EXPECT_CALL(*deps, incompatible(_, _)).Times(0);
|
||||
EXPECT_CALL(*deps, invalidHello()).Times(0);
|
||||
|
||||
helloBack.handleHello(&stream, clientName);
|
||||
}
|
||||
|
||||
TEST(HelloBackTests, handleHello_barrierProtocolCurrent_validMessage)
|
||||
{
|
||||
auto deps = std::make_shared<NiceMock<MockDeps>>();
|
||||
HelloBack helloBack(deps, 1, 2);
|
||||
NiceMock<MockStream> stream;
|
||||
const std::string clientName = "stub";
|
||||
|
||||
setupMockHelloRead(stream, "Barrier", 1, 2);
|
||||
|
||||
EXPECT_CALL(*deps, incompatible(_, _)).Times(0);
|
||||
EXPECT_CALL(*deps, invalidHello()).Times(0);
|
||||
|
||||
helloBack.handleHello(&stream, clientName);
|
||||
}
|
||||
|
||||
TEST(HelloBackTests, handleHello_synergyProtocolOlder_validMessage)
|
||||
{
|
||||
auto deps = std::make_shared<NiceMock<MockDeps>>();
|
||||
HelloBack helloBack(deps, 1, 2);
|
||||
NiceMock<MockStream> stream;
|
||||
const std::string clientName = "stub";
|
||||
|
||||
setupMockHelloRead(stream, "Synergy", 1, 1);
|
||||
|
||||
EXPECT_CALL(*deps, incompatible(1, 1)).Times(1);
|
||||
|
||||
helloBack.handleHello(&stream, clientName);
|
||||
}
|
||||
|
||||
TEST(HelloBackTests, handleHello_synergyProtocolCurrent_wroteHelloBack)
|
||||
{
|
||||
auto deps = std::make_shared<NiceMock<MockDeps>>();
|
||||
HelloBack helloBack(deps, 1, 2);
|
||||
NiceMock<MockStream> stream;
|
||||
const std::string clientName = "test client";
|
||||
|
||||
setupMockHelloRead(stream, "Synergy", 1, 2);
|
||||
|
||||
setupMockHelloBackWrite(stream, "Synergy", 1, 2, "test client");
|
||||
|
||||
helloBack.handleHello(&stream, clientName);
|
||||
}
|
||||
|
||||
TEST(HelloBackTests, handleHello_barrierProtocolCurrent_wroteHelloBack)
|
||||
{
|
||||
auto deps = std::make_shared<NiceMock<MockDeps>>();
|
||||
HelloBack helloBack(deps, 1, 2);
|
||||
NiceMock<MockStream> stream;
|
||||
const std::string clientName = "test client";
|
||||
|
||||
setupMockHelloRead(stream, "Barrier", 1, 2);
|
||||
|
||||
setupMockHelloBackWrite(stream, "Barrier", 1, 2, "test client");
|
||||
|
||||
helloBack.handleHello(&stream, clientName);
|
||||
}
|
||||
|
||||
// If the client is protocol version 1.8 and the server is 1.6, the client
|
||||
// should downgrade and respond with the server version.
|
||||
TEST(HelloBackTests, handleHello_synergyProtocolCompat_wroteHelloBack)
|
||||
{
|
||||
auto deps = std::make_shared<NiceMock<MockDeps>>();
|
||||
HelloBack helloBack(deps, 1, 8);
|
||||
NiceMock<MockStream> stream;
|
||||
const std::string clientName = "test client";
|
||||
|
||||
setupMockHelloRead(stream, "Synergy", 1, 6);
|
||||
|
||||
setupMockHelloBackWrite(stream, "Synergy", 1, 6, "test client");
|
||||
|
||||
helloBack.handleHello(&stream, clientName);
|
||||
}
|
||||
Loading…
Reference in a new issue