refactor: Remove old Windows TCP IPC implementation (replaced by Qt equivalent)

This commit is contained in:
Nick Bolton
2025-02-10 20:27:49 +00:00
parent a3b0ec28fc
commit 5a7f6bd1c0
62 changed files with 19 additions and 2685 deletions

View File

@ -32,7 +32,6 @@ target_link_libraries(
io
mt
net
ipc
platform
server
app

View File

@ -27,7 +27,6 @@ target_link_libraries(
io
mt
net
ipc
platform
server
app

View File

@ -21,7 +21,6 @@ if(WIN32)
arch
base
io
ipc
mt
net
platform

View File

@ -18,7 +18,6 @@
#include "ServerConfig.h"
#include "VersionChecker.h"
#include "common/ipc.h"
#include "gui/config/AppConfig.h"
#include "gui/config/ConfigScopes.h"
#include "gui/config/ServerConfigDialogState.h"
@ -146,7 +145,6 @@ private:
void setIcon();
bool checkForApp(int which, QString &app);
void setStatus(const QString &status);
void sendIpcMessage(IpcMessageType type, const char *buffer, bool showErrors);
void updateFromLogLine(const QString &line);
QString getIPAddresses() const;
void enableServer(bool enable);

View File

@ -32,7 +32,6 @@ target_link_libraries(
io
mt
net
ipc
platform
server
app

View File

@ -9,7 +9,6 @@ add_subdirectory(client)
add_subdirectory(common)
add_subdirectory(deskflow)
add_subdirectory(io)
add_subdirectory(ipc)
add_subdirectory(mt)
add_subdirectory(net)
add_subdirectory(platform)

View File

@ -6,7 +6,6 @@
*/
#include "base/Event.h"
#include "base/EventQueue.h"
//
// Event

View File

@ -8,21 +8,17 @@
#include "base/EventQueue.h"
#include "arch/Arch.h"
#include "base/EventTypes.h"
#include "base/IEventJob.h"
#include "base/Log.h"
#include "base/SimpleEventQueueBuffer.h"
#include "base/Stopwatch.h"
#include "base/XBase.h"
#include "mt/Lock.h"
#include "mt/Mutex.h"
#include <stdexcept>
EVENT_TYPE_ACCESSOR(Client)
EVENT_TYPE_ACCESSOR(IStream)
EVENT_TYPE_ACCESSOR(IpcClient)
EVENT_TYPE_ACCESSOR(IpcClientProxy)
EVENT_TYPE_ACCESSOR(IpcServer)
EVENT_TYPE_ACCESSOR(IpcServerProxy)
EVENT_TYPE_ACCESSOR(IDataSocket)
EVENT_TYPE_ACCESSOR(IListenSocket)
EVENT_TYPE_ACCESSOR(ISocket)
@ -55,10 +51,6 @@ EventQueue::EventQueue()
m_nextType(Event::kLast),
m_typesForClient(NULL),
m_typesForIStream(NULL),
m_typesForIpcClient(NULL),
m_typesForIpcClientProxy(NULL),
m_typesForIpcServer(NULL),
m_typesForIpcServerProxy(NULL),
m_typesForIDataSocket(NULL),
m_typesForIListenSocket(NULL),
m_typesForISocket(NULL),

View File

@ -130,10 +130,6 @@ public:
//
ClientEvents &forClient();
IStreamEvents &forIStream();
IpcClientEvents &forIpcClient();
IpcClientProxyEvents &forIpcClientProxy();
IpcServerEvents &forIpcServer();
IpcServerProxyEvents &forIpcServerProxy();
IDataSocketEvents &forIDataSocket();
IListenSocketEvents &forIListenSocket();
ISocketEvents &forISocket();
@ -153,10 +149,6 @@ public:
private:
ClientEvents *m_typesForClient;
IStreamEvents *m_typesForIStream;
IpcClientEvents *m_typesForIpcClient;
IpcClientProxyEvents *m_typesForIpcClientProxy;
IpcServerEvents *m_typesForIpcServer;
IpcServerProxyEvents *m_typesForIpcServerProxy;
IDataSocketEvents *m_typesForIDataSocket;
IListenSocketEvents *m_typesForIListenSocket;
ISocketEvents *m_typesForISocket;

View File

@ -45,26 +45,6 @@ REGISTER_EVENT(IStream, inputShutdown)
REGISTER_EVENT(IStream, outputShutdown)
REGISTER_EVENT(IStream, inputFormatError)
//
// IpcClient
//
REGISTER_EVENT(IpcClient, connected)
REGISTER_EVENT(IpcClient, messageReceived)
//
// IpcClientProxy
//
REGISTER_EVENT(IpcClientProxy, messageReceived)
REGISTER_EVENT(IpcClientProxy, disconnected)
//
// IpcServerProxy
//
REGISTER_EVENT(IpcServerProxy, messageReceived)
//
// IDataSocket
//
@ -167,13 +147,6 @@ REGISTER_EVENT(IScreen, shapeChanged)
REGISTER_EVENT(IScreen, suspend)
REGISTER_EVENT(IScreen, resume)
//
// IpcServer
//
REGISTER_EVENT(IpcServer, clientConnected)
REGISTER_EVENT(IpcServer, messageReceived)
//
// Clipboard
//

View File

@ -145,94 +145,6 @@ private:
Event::Type m_inputFormatError;
};
class IpcClientEvents : public EventTypes
{
public:
IpcClientEvents() : m_connected(Event::kUnknown), m_messageReceived(Event::kUnknown)
{
}
//! @name accessors
//@{
//! Raised when the socket is connected.
Event::Type connected();
//! Raised when a message is received.
Event::Type messageReceived();
//@}
private:
Event::Type m_connected;
Event::Type m_messageReceived;
};
class IpcClientProxyEvents : public EventTypes
{
public:
IpcClientProxyEvents() : m_messageReceived(Event::kUnknown), m_disconnected(Event::kUnknown)
{
}
//! @name accessors
//@{
//! Raised when the server receives a message from a client.
Event::Type messageReceived();
//! Raised when the client disconnects from the server.
Event::Type disconnected();
//@}
private:
Event::Type m_messageReceived;
Event::Type m_disconnected;
};
class IpcServerEvents : public EventTypes
{
public:
IpcServerEvents() : m_clientConnected(Event::kUnknown), m_messageReceived(Event::kUnknown)
{
}
//! @name accessors
//@{
//! Raised when we have created the client proxy.
Event::Type clientConnected();
//! Raised when a message is received through a client proxy.
Event::Type messageReceived();
//@}
private:
Event::Type m_clientConnected;
Event::Type m_messageReceived;
};
class IpcServerProxyEvents : public EventTypes
{
public:
IpcServerProxyEvents() : m_messageReceived(Event::kUnknown)
{
}
//! @name accessors
//@{
//! Raised when the client receives a message from the server.
Event::Type messageReceived();
//@}
private:
Event::Type m_messageReceived;
};
class IDataSocketEvents : public EventTypes
{
public:

View File

@ -21,10 +21,6 @@ class EventQueueTimer;
// Event type registration classes.
class ClientEvents;
class IStreamEvents;
class IpcClientEvents;
class IpcClientProxyEvents;
class IpcServerEvents;
class IpcServerProxyEvents;
class IDataSocketEvents;
class IListenSocketEvents;
class ISocketEvents;
@ -216,10 +212,6 @@ public:
virtual ClientEvents &forClient() = 0;
virtual IStreamEvents &forIStream() = 0;
virtual IpcClientEvents &forIpcClient() = 0;
virtual IpcClientProxyEvents &forIpcClientProxy() = 0;
virtual IpcServerEvents &forIpcServer() = 0;
virtual IpcServerProxyEvents &forIpcServerProxy() = 0;
virtual IDataSocketEvents &forIDataSocket() = 0;
virtual IListenSocketEvents &forIListenSocket() = 0;
virtual ISocketEvents &forISocket() = 0;

View File

@ -8,7 +8,6 @@ configure_file(constants.h.in constants.h @ONLY)
add_library(common INTERFACE
common.h
IInterface.h
ipc.h
stdbitset.h
stddeque.h
stdexcept.h

View File

@ -45,7 +45,7 @@ enum
#if WINAPI_MSWINDOWS
namespace deskflow::common {
const auto kCloseEventName = "Global\\DeskflowCloseEvent";
const auto kCloseEventName = "Global\\DeskflowClose";
}
#endif

View File

@ -1,57 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include "common.h"
enum class IpcMessageType : uint8_t
{
Hello,
HelloBack,
LogLine,
Command,
Shutdown,
Setting
};
enum class IpcClientType
{
Unknown,
GUI,
Node
};
const auto kIpcHost = "127.0.0.1";
const auto kIpcPort = 24801;
// handshake: node/gui -> daemon
// $1 = type, the client identifies it's self as gui or core (server/client).
const auto kIpcMsgHello = "IHEL%1i";
// handshake: daemon -> node/gui
// the daemon responds to the handshake.
const auto kIpcMsgHelloBack = "IHEL";
// log line: daemon -> gui
// $1 = aggregate log lines collected from core (server/client) or the daemon
// itself.
const auto kIpcMsgLogLine = "ILOG%s";
// command: gui -> daemon
// $1 = command; the command for the daemon to launch, typically the full
// path to core (server/client). $2 = true when process must be elevated on ms
// windows.
const auto kIpcMsgCommand = "ICMD%s%1i";
// shutdown: daemon -> node
// the daemon tells core (server/client) to shut down gracefully.
const auto kIpcMsgShutdown = "ISDN";
// set setting: gui -> daemon
// $1 = setting name
// $2 = setting value
const auto kIpcMsgSetting = "SSET%s%s";

View File

@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 - 2025 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
@ -9,36 +9,23 @@
#include "DisplayInvalidException.h"
#include "arch/Arch.h"
#include "arch/XArch.h"
#include "base/EventQueue.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "base/XBase.h"
#include "base/log_outputters.h"
#include "common/constants.h"
#include "common/ipc.h"
#include "deskflow/ArgsBase.h"
#include "deskflow/Config.h"
#include "deskflow/XDeskflow.h"
#include "deskflow/protocol_types.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServerProxy.h"
#include <thread>
#if SYSAPI_WIN32
#include "arch/win32/ArchMiscWindows.h"
#include "base/IEventQueue.h"
#include "base/TMethodJob.h"
#endif
#if WINAPI_CARBON
#include "platform/OSXDragSimulator.h"
#endif
#include <charconv>
#include <filesystem>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <stdio.h>
#include <vector>
@ -64,7 +51,6 @@ App::App(IEventQueue *events, deskflow::ArgsBase *args)
m_args(args),
m_fileLog(nullptr),
m_appUtil(events),
m_ipcClient(nullptr),
m_socketMultiplexer(nullptr)
{
assert(s_instance == nullptr);
@ -208,32 +194,6 @@ void App::initApp(int argc, const char **argv)
loadConfig();
}
void App::initIpcClient()
{
m_ipcClient = new IpcClient(m_events, m_socketMultiplexer);
m_ipcClient->connect();
m_events->adoptHandler(
m_events->forIpcClient().messageReceived(), m_ipcClient, new TMethodEventJob<App>(this, &App::handleIpcMessage)
);
}
void App::cleanupIpcClient()
{
m_ipcClient->disconnect();
m_events->removeHandler(m_events->forIpcClient().messageReceived(), m_ipcClient);
delete m_ipcClient;
}
void App::handleIpcMessage(const Event &e, void *)
{
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
if (m->type() == IpcMessageType::Shutdown) {
LOG((CLOG_INFO "got ipc shutdown message"));
m_events->addEvent(Event(Event::kQuit));
}
}
void App::runEventsLoop(void *)
{
m_events->loop();

View File

@ -1,6 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 - 2025 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
@ -11,7 +11,6 @@
#include "base/Log.h"
#include "common/common.h"
#include "deskflow/IApp.h"
#include "ipc/IpcClient.h"
#if SYSAPI_WIN32
#include "deskflow/win32/AppUtilWindows.h"
@ -20,7 +19,6 @@
#endif
#include <stdexcept>
#include <thread>
namespace deskflow {
class Screen;
@ -110,12 +108,7 @@ public:
void (*m_bye)(int);
private:
void handleIpcMessage(const Event &, void *);
protected:
void initIpcClient();
void cleanupIpcClient();
void runEventsLoop(void *);
bool m_suspended;
@ -126,7 +119,6 @@ private:
static App *s_instance;
FileLogOutputter *m_fileLog;
ARCH_APP_UTIL m_appUtil;
IpcClient *m_ipcClient;
SocketMultiplexer *m_socketMultiplexer;
};

View File

@ -188,8 +188,6 @@ bool ArgParser::parseGenericArgs(int argc, const char *const *argv, int &i)
m_app->version();
}
argsBase().m_shouldExitOk = true;
} else if (isArg(i, argc, argv, nullptr, "--ipc")) {
argsBase().m_enableIpc = true;
} else if (isArg(i, argc, argv, nullptr, "--server")) {
// HACK: stop error happening when using portable (deskflowp)
} else if (isArg(i, argc, argv, nullptr, "--client")) {

View File

@ -56,8 +56,8 @@ public:
/// @brief The name of the current computer
std::string m_name;
/// @brief Tell the client to talk through IPC to the daemon
bool m_enableIpc = false;
/// @brief Should the app add a tray icon
bool m_disableTray = false;
/// @brief Should drag drop support be enabled
bool m_enableDragDrop = false;

View File

@ -1,5 +1,5 @@
# SPDX-FileCopyrightText: 2024 Chris Rizzitello <sithlord48@gmail.com>
# SPDX-FileCopyrightText: 2012 - 2024 Symless Ltd
# SPDX-FileCopyrightText: 2012 - 2025 Symless Ltd
# SPDX-FileCopyrightText: 2009 - 2012 Nick Bolton
# SPDX-License-Identifier: MIT
@ -170,7 +170,6 @@ if(UNIX)
PRIVATE
arch
client
ipc
net
base
platform

View File

@ -454,12 +454,6 @@ int ClientApp::mainLoop()
// start client, etc
appUtil().startNode();
// init ipc client after node start, since create a new screen wipes out
// the event queue (the screen ctors call adoptBuffer).
if (argsBase().m_enableIpc) {
initIpcClient();
}
// run event loop. if startClient() failed we're supposed to retry
// later. the timer installed by startClient() will take care of
// that.
@ -486,10 +480,6 @@ int ClientApp::mainLoop()
updateStatus();
LOG((CLOG_NOTE "stopped client"));
if (argsBase().m_enableIpc) {
cleanupIpcClient();
}
return kExitSuccess;
}

View File

@ -4,26 +4,13 @@
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
// TODO: split this class into windows and unix to get rid
// of all the #ifdefs!
#include "deskflow/DaemonApp.h"
#include "arch/XArch.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "base/log_outputters.h"
#include "common/constants.h"
#include "common/ipc.h"
#include "deskflow/App.h"
#include "deskflow/ArgParser.h"
#include "deskflow/ClientArgs.h"
#include "deskflow/ServerArgs.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcLogOutputter.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcSettingMessage.h"
#include "net/SocketMultiplexer.h"
#if SYSAPI_WIN32
@ -50,16 +37,6 @@ using namespace deskflow::core;
const char *const kLogFilename = "deskflow-daemon.log";
namespace {
void updateSetting(const IpcMessage &message)
{
try {
auto setting = static_cast<const IpcSettingMessage &>(message);
ARCH->setting(setting.getName(), setting.getValue());
} catch (const XArch &e) {
LOG((CLOG_ERR "failed to save setting: %s", e.what()));
}
}
bool isServerCommandLine(const std::vector<std::string> &cmd)
{
auto isServer = false;
@ -76,7 +53,7 @@ bool isServerCommandLine(const std::vector<std::string> &cmd)
int mainLoopStatic()
{
DaemonApp::instance().mainLoop(true);
DaemonApp::instance().mainLoop();
return kExitSuccess;
}
@ -108,7 +85,7 @@ void DaemonApp::run()
// run process in foreground instead of daemonizing.
// useful for debugging.
mainLoop(false, m_foreground);
mainLoop(m_foreground);
} else {
#if SYSAPI_WIN32
LOG((CLOG_NOTE "daemonizing windows service"));
@ -260,7 +237,7 @@ DaemonApp::InitResult DaemonApp::init(IEventQueue *events, int argc, char **argv
return FatalError;
}
void DaemonApp::mainLoop(bool logToFile, bool foreground)
void DaemonApp::mainLoop(bool foreground)
{
if (m_events == nullptr) {
throw XDeskflow("event queue not set");
@ -269,17 +246,12 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground)
try {
DAEMON_RUNNING(true);
if (logToFile) {
m_fileLogOutputter = new FileLogOutputter(logFilename().c_str()); // NOSONAR -- Adopted by `Log`
CLOG->insert(m_fileLogOutputter);
}
m_fileLogOutputter = new FileLogOutputter(logFilename().c_str()); // NOSONAR - Adopted by `Log`
CLOG->insert(m_fileLogOutputter);
#if SYSAPI_WIN32
m_watchdog = std::make_unique<MSWindowsWatchdog>(false, foreground);
m_watchdog->setFileLogOutputter(m_fileLogOutputter);
#endif
#if SYSAPI_WIN32
// install the platform event queue to handle service stop events.
m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events));
@ -293,14 +265,13 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground)
m_watchdog->startAsync();
#endif
m_events->loop();
#if SYSAPI_WIN32
m_watchdog->stop();
#endif
CLOG->remove(m_ipcLogOutputter.get());
DAEMON_RUNNING(false);
} catch (std::exception &e) {
LOG((CLOG_CRIT "an error occurred: %s", e.what()));

View File

@ -13,11 +13,8 @@
#include <QObject>
#include "common/common.h"
class Event;
class IEventQueue;
class IpcLogOutputter;
class FileLogOutputter;
class QLocalServer;
class QCoreApplication;
@ -49,15 +46,14 @@ public:
InitResult init(IEventQueue *events, int argc, char **argv);
void run();
void mainLoop(bool logToFile, bool foreground = false);
void restartCoreProcess();
void saveLogLevel(const QString &logLevel) const;
void mainLoop(bool foreground = false);
void setLogLevel(const QString &logLevel);
void setElevate(bool elevate);
void setCommand(const QString &command);
void applyWatchdogCommand() const;
void clearWatchdogCommand();
// Getters
std::string logFilename();
static DaemonApp &instance()
@ -79,7 +75,6 @@ private:
#endif
private:
std::unique_ptr<IpcLogOutputter> m_ipcLogOutputter;
IEventQueue *m_events = nullptr;
FileLogOutputter *m_fileLogOutputter = nullptr;
deskflow::core::ipc::DaemonIpcServer *m_ipcServer = nullptr;

View File

@ -706,12 +706,6 @@ int ServerApp::mainLoop()
// start server, etc
appUtil().startNode();
// init ipc client after node start, since create a new screen wipes out
// the event queue (the screen ctors call adoptBuffer).
if (argsBase().m_enableIpc) {
initIpcClient();
}
// handle hangup signal by reloading the server's configuration
ARCH->setSignalHandler(Arch::kHANGUP, &reloadSignalHandler, NULL);
m_events->adoptHandler(
@ -761,10 +755,6 @@ int ServerApp::mainLoop()
updateStatus();
LOG((CLOG_NOTE "stopped server"));
if (argsBase().m_enableIpc) {
cleanupIpcClient();
}
return kExitSuccess;
}

View File

@ -64,13 +64,6 @@ add_library(${target} STATIC
core/ServerMessage.h
core/WaylandWarnings.cpp
core/WaylandWarnings.h
ipc/IpcReader.cpp
ipc/IpcReader.h
ipc/IQIpcClient.cpp
ipc/IQIpcClient.h
ipc/QDataStreamProxy.h
ipc/QIpcClient.cpp
ipc/QIpcClient.h
ipc/DaemonIpcClient.cpp
ipc/DaemonIpcClient.h
proxy/QNetworkAccessManagerProxy.cpp

View File

@ -158,18 +158,6 @@ CoreProcess::CoreProcess(const IAppConfig &appConfig, const IServerConfig &serve
m_pDeps(deps),
m_daemonIpcClient{new ipc::DaemonIpcClient(this)}
{
if (m_appConfig.processMode() == ProcessMode::kService) {
connect(m_daemonIpcClient, &ipc::DaemonIpcClient::connected, this, &CoreProcess::daemonIpcClientConnected);
const auto logPath = requestDaemonLogPath();
if (!logPath.isEmpty()) {
qInfo() << "daemon log path:" << logPath;
m_daemonFileTail = new FileTail(logPath, this);
connect(m_daemonFileTail, &FileTail::newLine, this, &CoreProcess::handleLogLines);
}
}
connect(m_daemonIpcClient, &ipc::DaemonIpcClient::connected, this, &CoreProcess::daemonIpcClientConnected);
connect(&m_pDeps->process(), &QProcessProxy::finished, this, &CoreProcess::onProcessFinished);
@ -191,30 +179,6 @@ CoreProcess::CoreProcess(const IAppConfig &appConfig, const IServerConfig &serve
});
}
void CoreProcess::onIpcClientServiceReady()
{
if (m_processState == ProcessState::Starting) {
qDebug("service ready, continuing core process start");
start();
} else if (m_processState == ProcessState::Stopping) {
qDebug("service ready, continuing core process stop");
stop();
} else {
// This may happen when the IPC connection fails and then reconnects.
qWarning("ignoring service ready, process state is not starting or stopping");
}
}
void CoreProcess::onIpcClientError(const QString &text) const
{
qCritical().noquote() << text;
}
void CoreProcess::onIpcClientRead(const QString &text)
{
handleLogLines(text);
}
void CoreProcess::onProcessReadyReadStandardOutput()
{
if (m_pDeps->process()) {
@ -314,10 +278,6 @@ void CoreProcess::startProcessFromDaemon(const QString &app, const QStringList &
qFatal("core process must be in starting state");
}
if (!m_daemonIpcClient->isConnected()) {
m_daemonIpcClient->connectToServer();
}
QString commandQuoted = makeQuotedArgs(app, args);
qInfo("running command: %s", qPrintable(commandQuoted));
@ -506,8 +466,6 @@ void CoreProcess::cleanup()
if (isDesktop && isRunning) {
stop();
}
m_pDeps->ipcClient().disconnectFromHost();
}
bool CoreProcess::addGenericArgs(QStringList &args, const ProcessMode processMode) const
@ -518,9 +476,6 @@ bool CoreProcess::addGenericArgs(QStringList &args, const ProcessMode processMod
args << "--name" << m_appConfig.screenName();
if (processMode != ProcessMode::kDesktop) {
// tell client/server to talk to daemon through ipc.
args << "--ipc";
#if defined(Q_OS_WIN)
// tell the client/server to shut down when a ms windows desk
// is switched; this is because we may need to elevate or not

View File

@ -9,7 +9,6 @@
#include "gui/FileTail.h"
#include "gui/config/IAppConfig.h"
#include "gui/config/IServerConfig.h"
#include "gui/ipc/QIpcClient.h"
#include "gui/proxy/QProcessProxy.h"
#include <memory>
@ -31,7 +30,6 @@ class CoreProcess : public QObject
{
using IServerConfig = deskflow::gui::IServerConfig;
using QProcessProxy = deskflow::gui::proxy::QProcessProxy;
using IQIpcClient = deskflow::gui::ipc::IQIpcClient;
Q_OBJECT
@ -43,17 +41,12 @@ public:
{
return m_process;
}
virtual IQIpcClient &ipcClient()
{
return m_ipcClient;
}
virtual QString appPath(const QString &name) const;
virtual bool fileExists(const QString &path) const;
virtual QString getProfileRoot() const;
private:
QProcessProxy m_process;
QIpcClient m_ipcClient;
};
enum class Mode
@ -136,9 +129,6 @@ signals:
void secureSocket(bool enabled);
private slots:
void onIpcClientServiceReady();
void onIpcClientRead(const QString &text);
void onIpcClientError(const QString &text) const;
void onProcessFinished(int exitCode, QProcess::ExitStatus);
void onProcessReadyReadStandardOutput();
void onProcessReadyReadStandardError();

View File

@ -1,7 +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
*/
// empty .cpp for qt moc

View File

@ -1,32 +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 <QObject>
#include <QString>
#include "gui/config/ElevateMode.h"
namespace deskflow::gui::ipc {
class IQIpcClient : public QObject
{
Q_OBJECT
public:
~IQIpcClient() override = default;
virtual void sendHello() const = 0;
virtual void sendCommand(const QString &command, ElevateMode elevate) const = 0;
virtual void connectToHost() = 0;
virtual void disconnectFromHost() = 0;
virtual bool isConnected() const = 0;
signals:
void read(const QString &text);
void serviceReady();
};
} // namespace deskflow::gui::ipc

View File

@ -1,96 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "IpcReader.h"
#include "Logger.h"
#include "byte_utils.h"
#include "common/ipc.h"
#include <QByteArray>
#include <QMutex>
#include <QTcpSocket>
using namespace deskflow::gui;
IpcReader::IpcReader(QTcpSocket *socket) : m_Socket(socket)
{
}
void IpcReader::start() const
{
connect(m_Socket, &QTcpSocket::readyRead, this, &IpcReader::onSocketReadyRead);
}
void IpcReader::stop() const
{
disconnect(m_Socket, &QTcpSocket::readyRead, this, &IpcReader::onSocketReadyRead);
}
void IpcReader::onSocketReadyRead()
{
QMutexLocker locker(&m_Mutex);
logVerbose("ready read");
while (m_Socket->bytesAvailable()) {
logVerbose("bytes available");
char codeBuf[5];
readStream(codeBuf, 4);
codeBuf[4] = 0;
logVerbose(QString("ipc read: %1").arg(codeBuf));
if (memcmp(codeBuf, kIpcMsgLogLine, 4) == 0) {
logVerbose("reading log line");
char lenBuf[4];
readStream(lenBuf, 4);
int len = bytesToInt(lenBuf, 4);
std::vector<char> dataBuf(len);
readStream(dataBuf.data(), len);
QString text = QString::fromUtf8(dataBuf.data(), len);
Q_EMIT read(text);
} else if (memcmp(codeBuf, kIpcMsgHelloBack, 4) == 0) {
logVerbose("reading hello back");
Q_EMIT helloBack();
} else {
qCritical("aborting ipc read, message invalid");
return;
}
}
logVerbose("read done");
}
bool IpcReader::readStream(char *buffer, int length)
{
logVerbose("reading stream");
int read = 0;
while (read < length) {
int ask = length - read;
if (m_Socket->bytesAvailable() < ask) {
logVerbose("buffer too short, waiting");
m_Socket->waitForReadyRead(-1);
}
auto got = m_Socket->read(buffer, ask);
read += got;
logVerbose(QString("ask=%1 got=%2 read=%3").arg(ask).arg(got).arg(read));
if (got == -1) {
logVerbose("socket ended, aborting");
return false;
} else if (length - read > 0) {
logVerbose(QString("more remains, seek to %1").arg(got));
buffer += got;
}
}
return true;
}

View File

@ -1,37 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include <QMutex>
#include <QObject>
class QTcpSocket;
class IpcReader : public QObject
{
Q_OBJECT;
public:
explicit IpcReader(QTcpSocket *socket);
~IpcReader() override = default;
void start() const;
void stop() const;
signals:
void read(const QString &text);
void helloBack();
private:
bool readStream(char *buffer, int length);
private slots:
void onSocketReadyRead();
private:
QTcpSocket *m_Socket;
QMutex m_Mutex;
};

View File

@ -1,31 +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 <QTcpSocket>
/**
* @brief Useful for overriding QDataStream.
*/
class QDataStreamProxy
{
public:
explicit QDataStreamProxy() = default;
explicit QDataStreamProxy(QTcpSocket *socket) : m_Stream(std::make_unique<QDataStream>(socket))
{
}
virtual ~QDataStreamProxy() = default;
virtual qint64 writeRawData(const char *data, int len)
{
assert(m_Stream);
return m_Stream->writeRawData(data, len);
}
private:
std::unique_ptr<QDataStream> m_Stream;
};

View File

@ -1,165 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "QIpcClient.h"
#include "IpcReader.h"
#include "byte_utils.h"
#include "common/ipc.h"
#include <QDataStream>
#include <QHostAddress>
#include <QTimer>
#include <memory>
const auto kRetryInterval = 1000;
const auto kConnectTimeout = 5000;
using namespace deskflow::gui;
QIpcClient::QIpcClient(const StreamProvider &streamProvider) : m_streamProvider(streamProvider)
{
m_pSocket = std::make_unique<QTcpSocket>();
if (!m_streamProvider) {
m_streamProvider = [this]() { return std::make_shared<QDataStreamProxy>(m_pSocket.get()); };
}
connect(m_pSocket.get(), &QTcpSocket::connected, this, &QIpcClient::onSocketConnected);
connect(m_pSocket.get(), &QTcpSocket::errorOccurred, this, &QIpcClient::onSocketError);
m_pReader = std::make_unique<IpcReader>(m_pSocket.get());
connect(
m_pReader.get(), &IpcReader::read, this, //
&QIpcClient::onIpcReaderRead
);
connect(m_pReader.get(), &IpcReader::helloBack, this, &QIpcClient::onIpcReaderHelloBack);
}
void QIpcClient::onSocketConnected() const
{
sendHello();
}
void QIpcClient::connectToHost()
{
m_isConnecting = true;
qInfo("connecting to background service...");
const auto port = static_cast<quint16>(kIpcPort);
m_pSocket->connectToHost(QHostAddress(QHostAddress::LocalHost), port);
if (!m_readerStarted) {
m_pReader->start();
m_readerStarted = true;
}
QTimer::singleShot(kConnectTimeout, this, [this]() {
if (!m_isConnected) {
qCritical("ipc connection timeout");
}
});
}
void QIpcClient::disconnectFromHost()
{
m_pReader->stop();
m_pSocket->flush();
m_pSocket->close();
m_isConnecting = false;
m_isConnected = false;
qInfo("disconnected from background service");
}
void QIpcClient::onSocketError(QAbstractSocket::SocketError socketError)
{
QString text;
switch (socketError) {
case 0:
text = "connection refused";
break;
case 1:
text = "remote host closed";
break;
default:
text = QString("code=%1").arg(socketError);
break;
}
qWarning("ipc connection error, %s", qUtf8Printable(text));
m_isConnected = false;
QTimer::singleShot(kRetryInterval, this, &QIpcClient::onRetryConnect);
}
void QIpcClient::onRetryConnect()
{
if (m_isConnected) {
qDebug("ipc already connected, skipping retry");
return;
} else if (!m_isConnecting) {
qDebug("ipc not connecting, skipping retry");
return;
}
qInfo("retrying connection to background service...");
connectToHost();
}
void QIpcClient::sendHello() const
{
qDebug("sending ipc hello message");
auto stream = m_streamProvider();
stream->writeRawData(kIpcMsgHello, 4);
char typeBuf[1];
typeBuf[0] = static_cast<char>(IpcClientType::GUI);
stream->writeRawData(typeBuf, 1);
}
void QIpcClient::sendCommand(const QString &command, ElevateMode const elevate) const
{
qDebug("sending ipc command: %s", qUtf8Printable(command));
auto stream = m_streamProvider();
stream->writeRawData(kIpcMsgCommand, 4);
std::string stdStringCommand = command.toStdString();
const char *charCommand = stdStringCommand.c_str();
auto length = static_cast<int>(stdStringCommand.length());
QByteArray lenBuf = intToBytes(length);
if (lenBuf.size() != 4) {
qFatal("unexpected int buffer size: %lld", lenBuf.size());
}
stream->writeRawData(lenBuf, 4);
stream->writeRawData(charCommand, length);
char elevateBuf[1];
// see enum ElevateMode documentation for why this flag is mapped this way
elevateBuf[0] = (elevate == ElevateMode::kAlways) ? 1 : 0;
stream->writeRawData(elevateBuf, 1);
}
void QIpcClient::onIpcReaderHelloBack()
{
qDebug("ipc hello back received");
if (m_isConnected) {
qWarning("ipc already connected, ignoring hello back");
return;
}
m_isConnected = true;
Q_EMIT serviceReady();
}
void QIpcClient::onIpcReaderRead(const QString &text)
{
Q_EMIT read(text);
}

View File

@ -1,54 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include <QAbstractSocket>
#include <QDataStream>
#include <QObject>
#include <QTcpSocket>
#include <memory>
#include "IpcReader.h"
#include "QDataStreamProxy.h"
#include "gui/config/ElevateMode.h"
#include "gui/ipc/IQIpcClient.h"
class IpcReader;
class QIpcClient : public deskflow::gui::ipc::IQIpcClient
{
Q_OBJECT
public:
using StreamProvider = std::function<std::shared_ptr<QDataStreamProxy>()>;
explicit QIpcClient(const StreamProvider &streamProvider = nullptr);
void sendHello() const override;
void sendCommand(const QString &command, ElevateMode elevate) const override;
void connectToHost() override;
void disconnectFromHost() override;
bool isConnected() const override
{
return m_isConnected;
}
private slots:
void onRetryConnect();
void onSocketConnected() const;
void onIpcReaderHelloBack();
void onSocketError(QAbstractSocket::SocketError error);
void onIpcReaderRead(const QString &text);
private:
std::unique_ptr<QTcpSocket> m_pSocket;
std::unique_ptr<IpcReader> m_pReader;
bool m_readerStarted = false;
StreamProvider m_streamProvider;
bool m_isConnected = false;
bool m_isConnecting = false;
};

View File

@ -1,32 +0,0 @@
# SPDX-FileCopyrightText: 2024 Chris Rizzitello <sithlord48@gmail.com>
# SPDX-FileCopyrightText: 2012 - 2024 Symless Ltd
# SPDX-FileCopyrightText: 2009 - 2012 Nick Bolton
# SPDX-License-Identifier: MIT
add_library(ipc STATIC
IpcClient.cpp
IpcClient.h
IpcClientProxy.cpp
IpcClientProxy.h
IpcLogOutputter.cpp
IpcLogOutputter.h
IpcMessage.cpp
IpcMessage.h
IpcServer.cpp
IpcServer.h
IpcServerProxy.cpp
IpcServerProxy.h
IpcSettingMessage.cpp
IpcSettingMessage.h
)
if(UNIX)
target_link_libraries(
ipc
arch
base
mt
io
net
app)
endif()

View File

@ -1,89 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "ipc/IpcClient.h"
#include "base/TMethodEventJob.h"
#include "common/ipc.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServerProxy.h"
//
// IpcClient
//
IpcClient::IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer)
: m_serverAddress(NetworkAddress(kIpcHost, kIpcPort)),
m_socket(events, socketMultiplexer),
m_server(nullptr),
m_events(events)
{
init();
}
IpcClient::IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer, int port)
: m_serverAddress(NetworkAddress(kIpcHost, port)),
m_socket(events, socketMultiplexer),
m_server(nullptr),
m_events(events)
{
init();
}
void IpcClient::init()
{
m_serverAddress.resolve();
}
IpcClient::~IpcClient()
{
}
void IpcClient::connect()
{
m_events->adoptHandler(
m_events->forIDataSocket().connected(), m_socket.getEventTarget(),
new TMethodEventJob<IpcClient>(this, &IpcClient::handleConnected)
);
m_socket.connect(m_serverAddress);
m_server = new IpcServerProxy(m_socket, m_events);
m_events->adoptHandler(
m_events->forIpcServerProxy().messageReceived(), m_server,
new TMethodEventJob<IpcClient>(this, &IpcClient::handleMessageReceived)
);
}
void IpcClient::disconnect()
{
m_events->removeHandler(m_events->forIDataSocket().connected(), m_socket.getEventTarget());
m_events->removeHandler(m_events->forIpcServerProxy().messageReceived(), m_server);
m_server->disconnect();
delete m_server;
m_server = nullptr;
}
void IpcClient::send(const IpcMessage &message)
{
assert(m_server != nullptr);
m_server->send(message);
}
void IpcClient::handleConnected(const Event &, void *)
{
m_events->addEvent(Event(m_events->forIpcClient().connected(), this, m_server, Event::kDontFreeData));
IpcHelloMessage message(IpcClientType::Node);
send(message);
}
void IpcClient::handleMessageReceived(const Event &e, void *)
{
Event event(m_events->forIpcClient().messageReceived(), this);
event.setDataObject(e.getDataObject());
m_events->addEvent(event);
}

View File

@ -1,54 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include "base/EventTypes.h"
#include "net/NetworkAddress.h"
#include "net/TCPSocket.h"
class IpcServerProxy;
class IpcMessage;
class IEventQueue;
class SocketMultiplexer;
//! IPC client for communication between daemon and GUI.
/*!
* See \ref IpcServer description.
*/
class IpcClient
{
public:
IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer);
IpcClient(IEventQueue *events, SocketMultiplexer *socketMultiplexer, int port);
virtual ~IpcClient();
//! @name manipulators
//@{
//! Connects to the IPC server at localhost.
void connect();
//! Disconnects from the IPC server.
void disconnect();
//! Sends a message to the server.
void send(const IpcMessage &message);
//@}
private:
void init();
void handleConnected(const Event &, void *);
void handleMessageReceived(const Event &, void *);
private:
NetworkAddress m_serverAddress;
TCPSocket m_socket;
IpcServerProxy *m_server;
IEventQueue *m_events;
};

View File

@ -1,179 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "ipc/IpcClientProxy.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "common/ipc.h"
#include "deskflow/ProtocolUtil.h"
#include "io/IStream.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcSettingMessage.h"
//
// IpcClientProxy
//
IpcClientProxy::IpcClientProxy(deskflow::IStream &stream, IEventQueue *events) : m_stream(stream), m_events(events)
{
m_events->adoptHandler(
m_events->forIStream().inputReady(), stream.getEventTarget(),
new TMethodEventJob<IpcClientProxy>(this, &IpcClientProxy::handleData)
);
m_events->adoptHandler(
m_events->forIStream().outputError(), stream.getEventTarget(),
new TMethodEventJob<IpcClientProxy>(this, &IpcClientProxy::handleWriteError)
);
m_events->adoptHandler(
m_events->forIStream().inputShutdown(), stream.getEventTarget(),
new TMethodEventJob<IpcClientProxy>(this, &IpcClientProxy::handleDisconnect)
);
m_events->adoptHandler(
m_events->forIStream().outputShutdown(), stream.getEventTarget(),
new TMethodEventJob<IpcClientProxy>(this, &IpcClientProxy::handleWriteError)
);
}
IpcClientProxy::~IpcClientProxy()
{
m_events->removeHandler(m_events->forIStream().inputReady(), m_stream.getEventTarget());
m_events->removeHandler(m_events->forIStream().outputError(), m_stream.getEventTarget());
m_events->removeHandler(m_events->forIStream().inputShutdown(), m_stream.getEventTarget());
m_events->removeHandler(m_events->forIStream().outputShutdown(), m_stream.getEventTarget());
// don't delete the stream while it's being used.
ARCH->lockMutex(m_readMutex);
ARCH->lockMutex(m_writeMutex);
delete &m_stream;
ARCH->unlockMutex(m_readMutex);
ARCH->unlockMutex(m_writeMutex);
ARCH->closeMutex(m_readMutex);
ARCH->closeMutex(m_writeMutex);
}
void IpcClientProxy::handleDisconnect(const Event &, void *)
{
disconnect();
LOG((CLOG_DEBUG "ipc client disconnected"));
}
void IpcClientProxy::handleWriteError(const Event &, void *)
{
disconnect();
LOG((CLOG_DEBUG "ipc client write error"));
}
void IpcClientProxy::handleData(const Event &, void *)
{
// don't allow the dtor to destroy the stream while we're using it.
ArchMutexLock lock(m_readMutex);
LOG((CLOG_DEBUG "start ipc handle data"));
uint8_t code[4];
uint32_t n = m_stream.read(code, 4);
while (n != 0) {
LOG((CLOG_DEBUG "ipc read: %c%c%c%c", code[0], code[1], code[2], code[3]));
IpcMessage *m = nullptr;
if (memcmp(code, kIpcMsgHello, 4) == 0) {
m = parseHello();
} else if (memcmp(code, kIpcMsgCommand, 4) == 0) {
m = parseCommand();
} else if (memcmp(code, kIpcMsgSetting, 4) == 0) {
m = parseSetting();
} else {
LOG((CLOG_ERR "invalid ipc message"));
disconnect();
}
// don't delete with this event; the data is passed to a new event.
Event e(m_events->forIpcClientProxy().messageReceived(), this, NULL, Event::kDontFreeData);
e.setDataObject(m);
m_events->addEvent(e);
n = m_stream.read(code, 4);
}
LOG((CLOG_DEBUG "finished ipc handle data"));
}
void IpcClientProxy::send(const IpcMessage &message)
{
// don't allow other threads to write until we've finished the entire
// message. stream write is locked, but only for that single write.
// also, don't allow the dtor to destroy the stream while we're using it.
ArchMutexLock lock(m_writeMutex);
LOG((CLOG_DEBUG4 "ipc write: %d", message.type()));
switch (message.type()) {
case IpcMessageType::LogLine: {
const IpcLogLineMessage &llm = static_cast<const IpcLogLineMessage &>(message);
const std::string logLine = llm.logLine();
ProtocolUtil::writef(&m_stream, kIpcMsgLogLine, &logLine);
break;
}
case IpcMessageType::Shutdown:
ProtocolUtil::writef(&m_stream, kIpcMsgShutdown);
break;
case IpcMessageType::HelloBack:
ProtocolUtil::writef(&m_stream, kIpcMsgHelloBack);
break;
default:
LOG((CLOG_ERR "ipc message not supported: %d", message.type()));
break;
}
}
IpcHelloMessage *IpcClientProxy::parseHello()
{
uint8_t type;
ProtocolUtil::readf(&m_stream, kIpcMsgHello + 4, &type);
m_clientType = static_cast<IpcClientType>(type);
// must be deleted by event handler.
return new IpcHelloMessage(m_clientType);
}
IpcCommandMessage *IpcClientProxy::parseCommand()
{
std::string command;
uint8_t elevate;
ProtocolUtil::readf(&m_stream, kIpcMsgCommand + 4, &command, &elevate);
// must be deleted by event handler.
return new IpcCommandMessage(command, elevate != 0);
}
IpcSettingMessage *IpcClientProxy::parseSetting() const
{
std::string name;
std::string value;
ProtocolUtil::readf(&m_stream, kIpcMsgSetting + 4, &name, &value);
// must be deleted by event handler.
return new IpcSettingMessage(name, value);
}
void IpcClientProxy::disconnect()
{
LOG((CLOG_DEBUG "ipc disconnect, closing stream"));
m_disconnecting = true;
m_stream.close();
m_events->addEvent(Event(m_events->forIpcClientProxy().disconnected(), this));
}

View File

@ -1,54 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include "arch/Arch.h"
#include "arch/IArchMultithread.h"
#include "base/Event.h"
#include "base/EventTypes.h"
#include "common/ipc.h"
namespace deskflow {
class IStream;
}
class IpcMessage;
class IpcCommandMessage;
class IpcSettingMessage;
class IpcHelloMessage;
class IEventQueue;
class IpcClientProxy
{
friend class IpcServer;
public:
IpcClientProxy(deskflow::IStream &stream, IEventQueue *events);
IpcClientProxy(IpcClientProxy const &) = delete;
IpcClientProxy(IpcClientProxy &&) = delete;
virtual ~IpcClientProxy();
IpcClientProxy &operator=(IpcClientProxy const &) = delete;
IpcClientProxy &operator=(IpcClientProxy &&) = delete;
private:
void send(const IpcMessage &message);
void handleData(const Event &, void *);
void handleDisconnect(const Event &, void *);
void handleWriteError(const Event &, void *);
IpcHelloMessage *parseHello();
IpcCommandMessage *parseCommand();
IpcSettingMessage *parseSetting() const;
void disconnect();
private:
deskflow::IStream &m_stream;
IEventQueue *m_events;
IpcClientType m_clientType = IpcClientType::Unknown;
bool m_disconnecting = false;
ArchMutex m_readMutex = ARCH->newMutex();
ArchMutex m_writeMutex = ARCH->newMutex();
};

View File

@ -1,203 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "ipc/IpcLogOutputter.h"
#include "arch/Arch.h"
#include "arch/XArch.h"
#include "base/Event.h"
#include "base/EventQueue.h"
#include "base/TMethodEventJob.h"
#include "base/TMethodJob.h"
#include "common/ipc.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServer.h"
#include "mt/Thread.h"
enum EIpcLogOutputter
{
kBufferMaxSize = 1000,
kMaxSendLines = 100,
kBufferRateWriteLimit = 1000, // writes per kBufferRateTime
kBufferRateTimeLimit = 1 // seconds
};
IpcLogOutputter::IpcLogOutputter(IpcServer &ipcServer, IpcClientType clientType, bool useThread)
: m_ipcServer(ipcServer),
m_bufferMutex(ARCH->newMutex()),
m_sending(false),
m_bufferThread(nullptr),
m_running(false),
m_notifyCond(ARCH->newCondVar()),
m_notifyMutex(ARCH->newMutex()),
m_bufferThreadId(0),
m_bufferWaiting(false),
m_bufferMaxSize(kBufferMaxSize),
m_bufferRateWriteLimit(kBufferRateWriteLimit),
m_bufferRateTimeLimit(kBufferRateTimeLimit),
m_bufferWriteCount(0),
m_bufferRateStart(ARCH->time()),
m_clientType(clientType),
m_runningMutex(ARCH->newMutex())
{
if (useThread) {
const auto outputter =
new TMethodJob<IpcLogOutputter>(this, &IpcLogOutputter::bufferThread); // NOSONAR -- Adopted by `Log`
m_bufferThread = new Thread(outputter);
}
}
IpcLogOutputter::~IpcLogOutputter()
{
close();
ARCH->closeMutex(m_bufferMutex);
if (m_bufferThread != nullptr) {
m_bufferThread->cancel();
m_bufferThread->wait();
delete m_bufferThread;
}
ARCH->closeCondVar(m_notifyCond);
ARCH->closeMutex(m_notifyMutex);
}
void IpcLogOutputter::open(const char *title)
{
}
void IpcLogOutputter::close()
{
if (m_bufferThread != nullptr) {
ArchMutexLock lock(m_runningMutex);
m_running = false;
notifyBuffer();
m_bufferThread->wait(5);
}
}
void IpcLogOutputter::show(bool showIfEmpty)
{
}
bool IpcLogOutputter::write(ELevel, const char *text)
{
// ignore events from the buffer thread (would cause recursion).
if (m_bufferThread != nullptr && Thread::getCurrentThread().getID() == m_bufferThreadId) {
return true;
}
appendBuffer(text);
notifyBuffer();
return true;
}
void IpcLogOutputter::appendBuffer(const std::string &text)
{
ArchMutexLock lock(m_bufferMutex);
double elapsed = ARCH->time() - m_bufferRateStart;
if (elapsed < m_bufferRateTimeLimit) {
if (m_bufferWriteCount >= m_bufferRateWriteLimit) {
// discard the log line if we've logged too much.
return;
}
} else {
m_bufferWriteCount = 0;
m_bufferRateStart = ARCH->time();
}
if (m_buffer.size() >= m_bufferMaxSize) {
// if the queue is exceeds size limit,
// throw away the oldest item
m_buffer.pop_front();
}
m_buffer.push_back(text);
m_bufferWriteCount++;
}
bool IpcLogOutputter::isRunning()
{
ArchMutexLock lock(m_runningMutex);
return m_running;
}
void IpcLogOutputter::bufferThread(void *)
{
m_bufferThreadId = m_bufferThread->getID();
m_running = true;
try {
while (isRunning()) {
if (m_buffer.empty() || !m_ipcServer.hasClients(m_clientType)) {
ArchMutexLock lock(m_notifyMutex);
ARCH->waitCondVar(m_notifyCond, m_notifyMutex, -1);
}
sendBuffer();
}
} catch (XArch &e) {
LOG((CLOG_ERR "ipc log buffer thread error, %s", e.what()));
}
LOG((CLOG_DEBUG "ipc log buffer thread finished"));
}
void IpcLogOutputter::notifyBuffer()
{
ArchMutexLock lock(m_notifyMutex);
ARCH->broadcastCondVar(m_notifyCond);
}
std::string IpcLogOutputter::getChunk(size_t count)
{
ArchMutexLock lock(m_bufferMutex);
if (m_buffer.size() < count) {
count = m_buffer.size();
}
std::string chunk;
for (size_t i = 0; i < count; i++) {
chunk.append(m_buffer.front());
chunk.append("\n");
m_buffer.pop_front();
}
return chunk;
}
void IpcLogOutputter::sendBuffer()
{
if (m_buffer.empty() || !m_ipcServer.hasClients(m_clientType)) {
return;
}
IpcLogLineMessage message(getChunk(kMaxSendLines));
m_sending = true;
m_ipcServer.send(message, IpcClientType::GUI);
m_sending = false;
}
void IpcLogOutputter::bufferMaxSize(uint16_t bufferMaxSize)
{
m_bufferMaxSize = bufferMaxSize;
}
uint16_t IpcLogOutputter::bufferMaxSize() const
{
return m_bufferMaxSize;
}
void IpcLogOutputter::bufferRateLimit(uint16_t writeLimit, double timeLimit)
{
m_bufferRateWriteLimit = writeLimit;
m_bufferRateTimeLimit = timeLimit;
}

View File

@ -1,109 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include "arch/Arch.h"
#include "arch/IArchMultithread.h"
#include "base/ILogOutputter.h"
#include "common/ipc.h"
#include <deque>
class IpcServer;
class Event;
class IpcClientProxy;
//! Write log to GUI over IPC
/*!
This outputter writes output to the GUI via IPC.
*/
class IpcLogOutputter : public ILogOutputter
{
public:
/*!
If \p useThread is \c true, the buffer will be sent using a thread.
If \p useThread is \c false, then the buffer needs to be sent manually
using the \c sendBuffer() function.
*/
IpcLogOutputter(IpcServer &ipcServer, IpcClientType clientType, bool useThread);
IpcLogOutputter(IpcLogOutputter const &) = delete;
virtual ~IpcLogOutputter();
// ILogOutputter overrides
virtual void open(const char *title);
virtual void close();
virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char *message);
//! @name manipulators
//@{
//! Notify that the buffer should be sent.
void notifyBuffer();
//! Set the buffer size
/*!
Set the maximum size of the buffer to protect memory
from runaway logging.
*/
void bufferMaxSize(uint16_t bufferMaxSize);
//! Set the rate limit
/*!
Set the maximum number of \p writeRate for every \p timeRate in seconds.
*/
void bufferRateLimit(uint16_t writeLimit, double timeLimit);
//! Send the buffer
/*!
Sends a chunk of the buffer to the IPC server, normally called
when threaded mode is on.
*/
void sendBuffer();
//@}
//! @name accessors
//@{
//! Get the buffer size
/*!
Returns the maximum size of the buffer.
*/
uint16_t bufferMaxSize() const;
//@}
private:
void init();
void bufferThread(void *);
std::string getChunk(size_t count);
void appendBuffer(const std::string &text);
bool isRunning();
private:
using Buffer = std::deque<std::string>;
IpcServer &m_ipcServer;
Buffer m_buffer;
ArchMutex m_bufferMutex;
bool m_sending;
Thread *m_bufferThread;
bool m_running;
ArchCond m_notifyCond;
ArchMutex m_notifyMutex;
bool m_bufferWaiting;
IArchMultithread::ThreadID m_bufferThreadId;
uint16_t m_bufferMaxSize;
uint16_t m_bufferRateWriteLimit;
double m_bufferRateTimeLimit;
uint16_t m_bufferWriteCount;
double m_bufferRateStart;
IpcClientType m_clientType;
ArchMutex m_runningMutex;
};

View File

@ -1,38 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "ipc/IpcMessage.h"
#include "common/ipc.h"
IpcMessage::IpcMessage(IpcMessageType type) : m_type(type)
{
}
IpcHelloMessage::IpcHelloMessage(IpcClientType clientType) : IpcMessage(IpcMessageType::Hello), m_clientType(clientType)
{
}
IpcHelloBackMessage::IpcHelloBackMessage() : IpcMessage(IpcMessageType::HelloBack)
{
}
IpcShutdownMessage::IpcShutdownMessage() : IpcMessage(IpcMessageType::Shutdown)
{
}
IpcLogLineMessage::IpcLogLineMessage(const std::string &logLine)
: IpcMessage(IpcMessageType::LogLine),
m_logLine(logLine)
{
}
IpcCommandMessage::IpcCommandMessage(const std::string &command, bool elevate)
: IpcMessage(IpcMessageType::Command),
m_command(command),
m_elevate(elevate)
{
}

View File

@ -1,99 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include "base/Event.h"
#include "common/ipc.h"
#include <string>
class IpcMessage : public EventData
{
public:
~IpcMessage() override = default;
//! Gets the message type ID.
IpcMessageType type() const
{
return m_type;
}
protected:
explicit IpcMessage(IpcMessageType type);
private:
IpcMessageType m_type;
};
class IpcHelloMessage : public IpcMessage
{
public:
explicit IpcHelloMessage(IpcClientType clientType);
~IpcHelloMessage() override = default;
//! Gets the message type ID.
IpcClientType clientType() const
{
return m_clientType;
}
private:
IpcClientType m_clientType;
};
class IpcHelloBackMessage : public IpcMessage
{
public:
explicit IpcHelloBackMessage();
~IpcHelloBackMessage() override = default;
};
class IpcShutdownMessage : public IpcMessage
{
public:
explicit IpcShutdownMessage();
~IpcShutdownMessage() override = default;
};
class IpcLogLineMessage : public IpcMessage
{
public:
explicit IpcLogLineMessage(const std::string &logLine);
~IpcLogLineMessage() override = default;
//! Gets the log line.
std::string logLine() const
{
return m_logLine;
}
private:
std::string m_logLine;
};
class IpcCommandMessage : public IpcMessage
{
public:
explicit IpcCommandMessage(const std::string &command, bool elevate);
~IpcCommandMessage() override = default;
//! Gets the command.
std::string command() const
{
return m_command;
}
//! Gets whether or not the process should be elevated on MS Windows.
bool elevate() const
{
return m_elevate;
}
private:
std::string m_command;
bool m_elevate;
};

View File

@ -1,167 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "ipc/IpcServer.h"
#include "base/Event.h"
#include "base/IEventQueue.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "common/ipc.h"
#include "io/IStream.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h"
#include "net/IDataSocket.h"
//
// IpcServer
//
IpcServer::IpcServer(IEventQueue *events, SocketMultiplexer *socketMultiplexer)
: m_mock(false),
m_events(events),
m_socketMultiplexer(socketMultiplexer),
m_socket(nullptr),
m_address(NetworkAddress(kIpcHost, kIpcPort))
{
init();
}
IpcServer::IpcServer(IEventQueue *events, SocketMultiplexer *socketMultiplexer, int port)
: m_mock(false),
m_events(events),
m_socketMultiplexer(socketMultiplexer),
m_address(NetworkAddress(kIpcHost, port))
{
init();
}
void IpcServer::init()
{
m_socket = new TCPListenSocket(m_events, m_socketMultiplexer, IArchNetwork::EAddressFamily::kINET);
m_clientsMutex = ARCH->newMutex();
m_address.resolve();
m_events->adoptHandler(
m_events->forIListenSocket().connecting(), m_socket,
new TMethodEventJob<IpcServer>(this, &IpcServer::handleClientConnecting)
);
}
IpcServer::~IpcServer()
{
if (m_mock) {
return;
}
if (m_socket != nullptr) {
delete m_socket;
}
ARCH->lockMutex(m_clientsMutex);
ClientList::iterator it;
for (it = m_clients.begin(); it != m_clients.end(); it++) {
deleteClient(*it);
}
m_clients.clear();
ARCH->unlockMutex(m_clientsMutex);
ARCH->closeMutex(m_clientsMutex);
m_events->removeHandler(m_events->forIListenSocket().connecting(), m_socket);
}
void IpcServer::listen()
{
m_socket->bind(m_address);
}
void IpcServer::handleClientConnecting(const Event &, void *)
{
deskflow::IStream *stream = m_socket->accept();
if (stream == NULL) {
return;
}
LOG((CLOG_DEBUG "accepted ipc client connection"));
ARCH->lockMutex(m_clientsMutex);
IpcClientProxy *proxy = new IpcClientProxy(*stream, m_events);
m_clients.push_back(proxy);
ARCH->unlockMutex(m_clientsMutex);
m_events->adoptHandler(
m_events->forIpcClientProxy().disconnected(), proxy,
new TMethodEventJob<IpcServer>(this, &IpcServer::handleClientDisconnected)
);
m_events->adoptHandler(
m_events->forIpcClientProxy().messageReceived(), proxy,
new TMethodEventJob<IpcServer>(this, &IpcServer::handleMessageReceived)
);
m_events->addEvent(Event(m_events->forIpcServer().clientConnected(), this, proxy, Event::kDontFreeData));
}
void IpcServer::handleClientDisconnected(const Event &e, void *)
{
IpcClientProxy *proxy = static_cast<IpcClientProxy *>(e.getTarget());
ArchMutexLock lock(m_clientsMutex);
m_clients.remove(proxy);
deleteClient(proxy);
LOG((CLOG_DEBUG "ipc client proxy removed, connected=%d", m_clients.size()));
}
void IpcServer::handleMessageReceived(const Event &e, void *)
{
Event event(m_events->forIpcServer().messageReceived(), this);
event.setDataObject(e.getDataObject());
m_events->addEvent(event);
}
void IpcServer::deleteClient(IpcClientProxy *proxy)
{
m_events->removeHandler(m_events->forIpcClientProxy().messageReceived(), proxy);
m_events->removeHandler(m_events->forIpcClientProxy().disconnected(), proxy);
delete proxy;
}
bool IpcServer::hasClients(IpcClientType clientType) const
{
ArchMutexLock lock(m_clientsMutex);
if (m_clients.empty()) {
return false;
}
ClientList::const_iterator it;
for (it = m_clients.begin(); it != m_clients.end(); it++) {
// at least one client is alive and type matches, there are clients.
IpcClientProxy *p = *it;
if (!p->m_disconnecting && p->m_clientType == clientType) {
return true;
}
}
// all clients must be disconnecting, no active clients.
return false;
}
void IpcServer::send(const IpcMessage &message, IpcClientType filterType)
{
ArchMutexLock lock(m_clientsMutex);
ClientList::iterator it;
for (it = m_clients.begin(); it != m_clients.end(); it++) {
IpcClientProxy *proxy = *it;
if (proxy->m_clientType == filterType) {
proxy->send(message);
}
}
}

View File

@ -1,85 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include "arch/Arch.h"
#include "base/EventTypes.h"
#include "common/ipc.h"
#include "net/NetworkAddress.h"
#include "net/TCPListenSocket.h"
#include <list>
class Event;
class IpcClientProxy;
class IpcMessage;
class IEventQueue;
class SocketMultiplexer;
//! IPC server for communication between daemon and GUI.
/*!
The IPC server listens on localhost. The IPC client runs on both the
client/server process or the GUI. The IPC server runs on the daemon process.
This allows the GUI to send config changes to the daemon and client/server,
and allows the daemon and client/server to send log data to the GUI.
*/
class IpcServer
{
public:
IpcServer(IEventQueue *events, SocketMultiplexer *socketMultiplexer);
IpcServer(IEventQueue *events, SocketMultiplexer *socketMultiplexer, int port);
IpcServer(IpcServer const &) = delete;
IpcServer(IpcServer &&) = delete;
virtual ~IpcServer();
IpcServer &operator=(IpcServer const &) = delete;
IpcServer &operator=(IpcServer &&) = delete;
//! @name manipulators
//@{
//! Opens a TCP socket only allowing local connections.
virtual void listen();
//! Send a message to all clients matching the filter type.
virtual void send(const IpcMessage &message, IpcClientType filterType);
//@}
//! @name accessors
//@{
//! Returns true when there are clients of the specified type connected.
virtual bool hasClients(IpcClientType clientType) const;
//@}
private:
void init();
void handleClientConnecting(const Event &, void *);
void handleClientDisconnected(const Event &, void *);
void handleMessageReceived(const Event &, void *);
void deleteClient(IpcClientProxy *proxy);
private:
using ClientList = std::list<IpcClientProxy *>;
bool m_mock;
IEventQueue *m_events;
SocketMultiplexer *m_socketMultiplexer;
TCPListenSocket *m_socket;
NetworkAddress m_address;
ClientList m_clients;
ArchMutex m_clientsMutex;
#ifdef TEST_ENV
public:
IpcServer() : m_mock(true), m_events(nullptr), m_socketMultiplexer(nullptr), m_socket(nullptr)
{
}
#endif
};

View File

@ -1,102 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "ipc/IpcServerProxy.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "common/ipc.h"
#include "deskflow/ProtocolUtil.h"
#include "io/IStream.h"
#include "ipc/IpcMessage.h"
//
// IpcServerProxy
//
IpcServerProxy::IpcServerProxy(deskflow::IStream &stream, IEventQueue *events) : m_stream(stream), m_events(events)
{
m_events->adoptHandler(
m_events->forIStream().inputReady(), stream.getEventTarget(),
new TMethodEventJob<IpcServerProxy>(this, &IpcServerProxy::handleData)
);
}
IpcServerProxy::~IpcServerProxy()
{
m_events->removeHandler(m_events->forIStream().inputReady(), m_stream.getEventTarget());
}
void IpcServerProxy::handleData(const Event &, void *)
{
LOG((CLOG_DEBUG "start ipc handle data"));
uint8_t code[4];
uint32_t n = m_stream.read(code, 4);
while (n != 0) {
LOG((CLOG_DEBUG "ipc read: %c%c%c%c", code[0], code[1], code[2], code[3]));
IpcMessage *m = nullptr;
if (memcmp(code, kIpcMsgLogLine, 4) == 0) {
m = parseLogLine();
} else if (memcmp(code, kIpcMsgShutdown, 4) == 0) {
m = new IpcShutdownMessage();
} else {
LOG((CLOG_ERR "invalid ipc message"));
disconnect();
}
// don't delete with this event; the data is passed to a new event.
Event e(m_events->forIpcServerProxy().messageReceived(), this, NULL, Event::kDontFreeData);
e.setDataObject(m);
m_events->addEvent(e);
n = m_stream.read(code, 4);
}
LOG((CLOG_DEBUG "finished ipc handle data"));
}
void IpcServerProxy::send(const IpcMessage &message)
{
LOG((CLOG_DEBUG4 "ipc write: %d", message.type()));
switch (message.type()) {
case IpcMessageType::Hello: {
const IpcHelloMessage &hm = static_cast<const IpcHelloMessage &>(message);
ProtocolUtil::writef(&m_stream, kIpcMsgHello, hm.clientType());
break;
}
case IpcMessageType::Command: {
const IpcCommandMessage &cm = static_cast<const IpcCommandMessage &>(message);
const std::string command = cm.command();
ProtocolUtil::writef(&m_stream, kIpcMsgCommand, &command);
break;
}
default:
LOG((CLOG_ERR "ipc message not supported: %d", message.type()));
break;
}
}
IpcLogLineMessage *IpcServerProxy::parseLogLine()
{
std::string logLine;
ProtocolUtil::readf(&m_stream, kIpcMsgLogLine + 4, &logLine);
// must be deleted by event handler.
return new IpcLogLineMessage(logLine);
}
void IpcServerProxy::disconnect()
{
LOG((CLOG_DEBUG "ipc disconnect, closing stream"));
m_stream.close();
}

View File

@ -1,39 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include "base/Event.h"
#include "base/EventTypes.h"
namespace deskflow {
class IStream;
}
class IpcMessage;
class IpcLogLineMessage;
class IEventQueue;
class IpcServerProxy
{
friend class IpcClient;
public:
IpcServerProxy(deskflow::IStream &stream, IEventQueue *events);
IpcServerProxy(IpcServerProxy const &) = delete;
virtual ~IpcServerProxy();
private:
void send(const IpcMessage &message);
void handleData(const Event &, void *);
IpcLogLineMessage *parseLogLine();
void disconnect();
private:
deskflow::IStream &m_stream;
IEventQueue *m_events;
};

View File

@ -1,25 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "IpcSettingMessage.h"
IpcSettingMessage::IpcSettingMessage(const std::string &name, const std::string &value)
: IpcMessage(IpcMessageType::Setting),
m_name(name),
m_value(value)
{
}
const std::string &IpcSettingMessage::getName() const
{
return m_name;
}
const std::string &IpcSettingMessage::getValue() const
{
return m_value;
}

View File

@ -1,38 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include "IpcMessage.h"
#include <string>
class IpcSettingMessage : public IpcMessage
{
public:
//!
//! \brief IpcSettingMessage constructor
//! \param name - setting name
//! \param value - setting value
//!
IpcSettingMessage(const std::string &name, const std::string &value);
//!
//! \brief getName is a getter for the setting name
//! \return setting name
//!
const std::string &getName() const;
//!
//! \brief getValue is a getter for the setting value
//! \return setting value
//!
const std::string &getValue() const;
private:
std::string m_name;
std::string m_value;
};

View File

@ -179,7 +179,6 @@ if(UNIX)
platform
io
net
ipc
app
client
${libs})

View File

@ -8,7 +8,6 @@
#include "arch/win32/XArchWindows.h"
#include "base/Log.h"
#include "ipc/IpcMessage.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>

View File

@ -1,7 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2009 Chris Schoeneman
* SPDX-FileCopyrightText: (C) 2012 - 2025 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
@ -13,12 +12,8 @@
#include "base/Log.h"
#include "base/TMethodJob.h"
#include "base/log_outputters.h"
#include "common/ipc.h"
#include "deskflow/App.h"
#include "deskflow/ArgsBase.h"
#include "ipc/IpcLogOutputter.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServer.h"
#include "mt/Thread.h"
#include <Shellapi.h>
@ -437,7 +432,7 @@ void MSWindowsWatchdog::outputLoop(void *)
// process output to the VS debug output window.
// we could use the MSWindowsDebugOutputter, but it's really fiddly to
// so, and there doesn't seem to be an advantage of doing that.
OutputDebugString(output.c_str());
OutputDebugString(buffer);
}
#endif
}

View File

@ -1,7 +1,6 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2009 Chris Schoeneman
* SPDX-FileCopyrightText: (C) 2012 - 2025 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
@ -19,8 +18,6 @@
#include <string>
class Thread;
class IpcLogOutputter;
class IpcServer;
class FileLogOutputter;
class MSWindowsWatchdog

View File

@ -140,7 +140,6 @@ macro(config_test_deps)
server
app
mt
ipc
gui
GTest::gtest
GTest::gmock

View File

@ -1,192 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
// TODO: fix, tests failing intermittently on mac.
#ifndef WINAPI_CARBON
#define TEST_ENV
#include "arch/Arch.h"
#include "base/EventQueue.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "base/TMethodJob.h"
#include "common/ipc.h"
#include "ipc/IpcClient.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServer.h"
#include "ipc/IpcServerProxy.h"
#include "mt/Thread.h"
#include "net/SocketMultiplexer.h"
#include "test/shared/TestEventQueue.h"
#include <gtest/gtest.h>
const int kTestPort = 24802;
class IpcTests : public ::testing::Test
{
public:
IpcTests();
virtual ~IpcTests();
void connectToServer_handleMessageReceived(const Event &, void *);
void sendMessageToServer_serverHandleMessageReceived(const Event &, void *);
void sendMessageToClient_serverHandleClientConnected(const Event &, void *);
void sendMessageToClient_clientHandleMessageReceived(const Event &, void *);
public:
SocketMultiplexer m_multiplexer;
bool m_connectToServer_helloMessageReceived;
bool m_connectToServer_hasClientNode;
IpcServer *m_connectToServer_server;
std::string m_sendMessageToServer_receivedString;
std::string m_sendMessageToClient_receivedString;
IpcClient *m_sendMessageToServer_client;
IpcServer *m_sendMessageToClient_server;
TestEventQueue m_events;
};
TEST_F(IpcTests, connectToServer)
{
SocketMultiplexer socketMultiplexer;
IpcServer server(&m_events, &socketMultiplexer, kTestPort);
server.listen();
m_connectToServer_server = &server;
m_events.adoptHandler(
m_events.forIpcServer().messageReceived(), &server,
new TMethodEventJob<IpcTests>(this, &IpcTests::connectToServer_handleMessageReceived)
);
IpcClient client(&m_events, &socketMultiplexer, kTestPort);
client.connect();
m_events.initQuitTimeout(5);
m_events.loop();
m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server);
m_events.cleanupQuitTimeout();
EXPECT_EQ(true, m_connectToServer_helloMessageReceived);
EXPECT_EQ(true, m_connectToServer_hasClientNode);
}
TEST_F(IpcTests, sendMessageToServer)
{
SocketMultiplexer socketMultiplexer;
IpcServer server(&m_events, &socketMultiplexer, kTestPort);
server.listen();
// event handler sends "test" command to server.
m_events.adoptHandler(
m_events.forIpcServer().messageReceived(), &server,
new TMethodEventJob<IpcTests>(this, &IpcTests::sendMessageToServer_serverHandleMessageReceived)
);
IpcClient client(&m_events, &socketMultiplexer, kTestPort);
client.connect();
m_sendMessageToServer_client = &client;
m_events.initQuitTimeout(5);
m_events.loop();
m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server);
m_events.cleanupQuitTimeout();
EXPECT_EQ("test", m_sendMessageToServer_receivedString);
}
TEST_F(IpcTests, sendMessageToClient)
{
SocketMultiplexer socketMultiplexer;
IpcServer server(&m_events, &socketMultiplexer, kTestPort);
server.listen();
m_sendMessageToClient_server = &server;
// event handler sends "test" log line to client.
m_events.adoptHandler(
m_events.forIpcServer().messageReceived(), &server,
new TMethodEventJob<IpcTests>(this, &IpcTests::sendMessageToClient_serverHandleClientConnected)
);
IpcClient client(&m_events, &socketMultiplexer, kTestPort);
client.connect();
m_events.adoptHandler(
m_events.forIpcClient().messageReceived(), &client,
new TMethodEventJob<IpcTests>(this, &IpcTests::sendMessageToClient_clientHandleMessageReceived)
);
m_events.initQuitTimeout(5);
m_events.loop();
m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server);
m_events.removeHandler(m_events.forIpcClient().messageReceived(), &client);
m_events.cleanupQuitTimeout();
EXPECT_EQ("test", m_sendMessageToClient_receivedString);
}
IpcTests::IpcTests()
: m_connectToServer_helloMessageReceived(false),
m_connectToServer_hasClientNode(false),
m_connectToServer_server(nullptr),
m_sendMessageToClient_server(nullptr),
m_sendMessageToServer_client(nullptr)
{
}
IpcTests::~IpcTests()
{
}
void IpcTests::connectToServer_handleMessageReceived(const Event &e, void *)
{
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
if (m->type() == IpcMessageType::Hello) {
m_connectToServer_hasClientNode = m_connectToServer_server->hasClients(IpcClientType::Node);
m_connectToServer_helloMessageReceived = true;
m_events.raiseQuitEvent();
}
}
void IpcTests::sendMessageToServer_serverHandleMessageReceived(const Event &e, void *)
{
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
if (m->type() == IpcMessageType::Hello) {
LOG((CLOG_DEBUG "client said hello, sending test to server"));
IpcCommandMessage m("test", true);
m_sendMessageToServer_client->send(m);
} else if (m->type() == IpcMessageType::Command) {
IpcCommandMessage *cm = static_cast<IpcCommandMessage *>(m);
LOG((CLOG_DEBUG "got ipc command message, %d", cm->command().c_str()));
m_sendMessageToServer_receivedString = cm->command();
m_events.raiseQuitEvent();
}
}
void IpcTests::sendMessageToClient_serverHandleClientConnected(const Event &e, void *)
{
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
if (m->type() == IpcMessageType::Hello) {
LOG((CLOG_DEBUG "client said hello, sending test to client"));
IpcLogLineMessage m("test");
m_sendMessageToClient_server->send(m, IpcClientType::Node);
}
}
void IpcTests::sendMessageToClient_clientHandleMessageReceived(const Event &e, void *)
{
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
if (m->type() == IpcMessageType::LogLine) {
IpcLogLineMessage *llm = static_cast<IpcLogLineMessage *>(m);
LOG((CLOG_DEBUG "got ipc log message, %d", llm->logLine().c_str()));
m_sendMessageToClient_receivedString = llm->logLine();
m_events.raiseQuitEvent();
}
}
#endif // WINAPI_CARBON

View File

@ -34,10 +34,6 @@ public:
MOCK_METHOD(void *, getSystemTarget, (), (override));
MOCK_METHOD(ClientEvents &, forClient, (), (override));
MOCK_METHOD(IStreamEvents &, forIStream, (), (override));
MOCK_METHOD(IpcClientEvents &, forIpcClient, (), (override));
MOCK_METHOD(IpcClientProxyEvents &, forIpcClientProxy, (), (override));
MOCK_METHOD(IpcServerEvents &, forIpcServer, (), (override));
MOCK_METHOD(IpcServerProxyEvents &, forIpcServerProxy, (), (override));
MOCK_METHOD(IDataSocketEvents &, forIDataSocket, (), (override));
MOCK_METHOD(IListenSocketEvents &, forIListenSocket, (), (override));
MOCK_METHOD(ISocketEvents &, forISocket, (), (override));

View File

@ -1,61 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2015 - 2016 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#pragma once
#include "arch/Arch.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServer.h"
#include <gmock/gmock.h>
using ::testing::_;
using ::testing::Invoke;
class IEventQueue;
class MockIpcServer : public IpcServer
{
public:
MockIpcServer() : m_sendCond(ARCH->newCondVar()), m_sendMutex(ARCH->newMutex())
{
}
~MockIpcServer()
{
if (m_sendCond != NULL) {
ARCH->closeCondVar(m_sendCond);
}
if (m_sendMutex != NULL) {
ARCH->closeMutex(m_sendMutex);
}
}
MOCK_METHOD(void, listen, (), (override));
MOCK_METHOD(void, send, (const IpcMessage &, IpcClientType), (override));
MOCK_METHOD(bool, hasClients, (IpcClientType), (const, override));
void delegateToFake()
{
ON_CALL(*this, send(_, _)).WillByDefault(Invoke(this, &MockIpcServer::mockSend));
}
void waitForSend()
{
ARCH->waitCondVar(m_sendCond, m_sendMutex, 5);
}
private:
void mockSend(const IpcMessage &, IpcClientType)
{
ArchMutexLock lock(m_sendMutex);
ARCH->broadcastCondVar(m_sendCond);
}
ArchCond m_sendCond;
ArchMutex m_sendMutex;
};

View File

@ -205,18 +205,6 @@ TEST_F(GenericArgsParsingTests, parseGenericArgs_versionCmd_showVersion)
EXPECT_EQ(1, i);
}
TEST_F(GenericArgsParsingTests, parseGenericArgs_ipcCmd_enableIpcTrue)
{
int i = 1;
const int argc = 2;
const char *kIpcCmd[argc] = {"stub", "--ipc"};
m_argParser->parseGenericArgs(argc, kIpcCmd, i);
EXPECT_EQ(true, argsBase.m_enableIpc);
EXPECT_EQ(1, i);
}
#ifndef WINAPI_XWINDOWS
TEST_F(GenericArgsParsingTests, parseGenericArgs_dragDropCmdOnNonLinux_enableDragDropTrue)
{

View File

@ -6,7 +6,6 @@
#include "gui/config/IAppConfig.h"
#include "gui/core/CoreProcess.h"
#include "gui/ipc/IQIpcClient.h"
#include "gui/proxy/QProcessProxy.h"
#include "shared/gui/mocks/AppConfigMock.h"
#include "shared/gui/mocks/ServerConfigMock.h"
@ -45,41 +44,23 @@ public:
MOCK_METHOD(QString, readAllStandardError, (), (override));
};
class QIpcClientMock : public ipc::IQIpcClient
{
public:
QIpcClientMock()
{
ON_CALL(*this, isConnected()).WillByDefault(Return(true));
}
MOCK_METHOD(void, sendHello, (), (const, override));
MOCK_METHOD(void, sendCommand, (const QString &command, ElevateMode elevate), (const, override));
MOCK_METHOD(void, connectToHost, (), (override));
MOCK_METHOD(void, disconnectFromHost, (), (override));
MOCK_METHOD(bool, isConnected, (), (const, override));
};
class DepsMock : public CoreProcess::Deps
{
public:
DepsMock()
{
ON_CALL(*this, process()).WillByDefault(ReturnRef(m_process));
ON_CALL(*this, ipcClient()).WillByDefault(ReturnRef(m_ipcClient));
ON_CALL(*this, appPath(_)).WillByDefault(Return("stub app path"));
ON_CALL(*this, fileExists(_)).WillByDefault(Return(true));
ON_CALL(*this, getProfileRoot()).WillByDefault(Return("stub profile"));
}
MOCK_METHOD(proxy::QProcessProxy &, process, (), (override));
MOCK_METHOD(ipc::IQIpcClient &, ipcClient, (), (override));
MOCK_METHOD(QString, appPath, (const QString &name), (const, override));
MOCK_METHOD(bool, fileExists, (const QString &path), (const, override));
MOCK_METHOD(QString, getProfileRoot, (), (const, override));
NiceMock<QProcessProxyMock> m_process;
NiceMock<QIpcClientMock> m_ipcClient;
};
class CoreProcessTests : public Test
@ -111,15 +92,6 @@ TEST_F(CoreProcessTests, start_serverDesktop_callsProcessStart)
m_coreProcess.start(ProcessMode::kDesktop);
}
TEST_F(CoreProcessTests, start_serverService_callsSendCommand)
{
m_coreProcess.setMode(CoreProcess::Mode::Server);
EXPECT_CALL(m_pDeps->m_ipcClient, sendCommand(_, _)).Times(1);
m_coreProcess.start(ProcessMode::kService);
}
TEST_F(CoreProcessTests, start_clientDesktop_callsProcessStart)
{
m_coreProcess.setMode(CoreProcess::Mode::Client);
@ -130,16 +102,6 @@ TEST_F(CoreProcessTests, start_clientDesktop_callsProcessStart)
m_coreProcess.start(ProcessMode::kDesktop);
}
TEST_F(CoreProcessTests, start_clientService_callsSendCommand)
{
m_coreProcess.setMode(CoreProcess::Mode::Client);
m_coreProcess.setAddress("stub address");
EXPECT_CALL(m_pDeps->m_ipcClient, sendCommand(_, _)).Times(1);
m_coreProcess.start(ProcessMode::kService);
}
TEST_F(CoreProcessTests, stop_serverDesktop_callsProcessClose)
{
m_coreProcess.setMode(CoreProcess::Mode::Server);
@ -150,16 +112,6 @@ TEST_F(CoreProcessTests, stop_serverDesktop_callsProcessClose)
m_coreProcess.stop(ProcessMode::kDesktop);
}
TEST_F(CoreProcessTests, stop_serverService_callsSendCommand)
{
m_coreProcess.setMode(CoreProcess::Mode::Server);
m_coreProcess.start();
EXPECT_CALL(m_pDeps->m_ipcClient, sendCommand(_, _)).Times(1);
m_coreProcess.stop(ProcessMode::kService);
}
TEST_F(CoreProcessTests, stop_clientDesktop_callsProcessClose)
{
m_coreProcess.setMode(CoreProcess::Mode::Client);
@ -171,17 +123,6 @@ TEST_F(CoreProcessTests, stop_clientDesktop_callsProcessClose)
m_coreProcess.stop(ProcessMode::kDesktop);
}
TEST_F(CoreProcessTests, stop_clientService_callsSendCommand)
{
m_coreProcess.setMode(CoreProcess::Mode::Client);
m_coreProcess.setAddress("stub address");
m_coreProcess.start();
EXPECT_CALL(m_pDeps->m_ipcClient, sendCommand(_, _)).Times(1);
m_coreProcess.stop(ProcessMode::kService);
}
TEST_F(CoreProcessTests, restart_serverDesktop_callsProcessStart)
{
ON_CALL(m_appConfig, processMode()).WillByDefault(Return(ProcessMode::kDesktop));

View File

@ -1,35 +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 "gui/ipc/QIpcClient.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
using testing::_;
using testing::StrEq;
namespace {
class MockStream : public QDataStreamProxy
{
public:
MOCK_METHOD(qint64, writeRawData, (const char *, int), (override));
};
} // namespace
TEST(QIpcClientTests, sendCommand_anyCommand_commandSent)
{
auto mockStream = std::make_shared<MockStream>();
QIpcClient::StreamProvider streamProvider = [&mockStream]() { return mockStream; };
EXPECT_CALL(*mockStream, writeRawData(_, _)).Times(3);
EXPECT_CALL(*mockStream, writeRawData(StrEq("test"), 4)).Times(1);
QIpcClient ipcClient(streamProvider);
ipcClient.sendCommand("test", ElevateMode::kAutomatic);
}

View File

@ -1,163 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2015 - 2016 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#define TEST_ENV
#include "test/mock/ipc/MockIpcServer.h"
#include "base/String.h"
#include "common/common.h"
#include "ipc/IpcLogOutputter.h"
#include "mt/Thread.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
// HACK: ipc logging only used on windows anyway
#if WINAPI_MSWINDOWS
using ::testing::_;
using ::testing::AtLeast;
using ::testing::Matcher;
using ::testing::MatcherCast;
using ::testing::Property;
using ::testing::Return;
using ::testing::StrEq;
using namespace deskflow;
// TODO Fix the IPC Tests for windows, see #6709
// Tests disabled due to gtest/gmock update causing build problems
// Decision to disable tests and create issue instead due to time constraints
// inline const Matcher<const IpcMessage&> IpcLogLineMessageEq(const std::string& s)
// {
// const Matcher<const IpcLogLineMessage&> m(
// Property(&IpcLogLineMessage::logLine, StrEq(s)));
// return MatcherCast<const IpcMessage&>(m);
// }
//
// TEST(IpcLogOutputterTests, write_threadingEnabled_bufferIsSent)
//{
// MockIpcServer mockServer;
// mockServer.delegateToFake();
//
// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
//
// EXPECT_CALL(mockServer, hasClients(_)).Times(AtLeast(3));
// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\n"),
// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock
// 2\n"), _)).Times(1);
//
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, true);
// outputter.write(kNOTE, "mock 1");
// mockServer.waitForSend();
// outputter.write(kNOTE, "mock 2");
// mockServer.waitForSend();
// }
//
// TEST(IpcLogOutputterTests, write_overBufferMaxSize_firstLineTruncated)
//{
// MockIpcServer mockServer;
//
// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
// EXPECT_CALL(mockServer, hasClients(_)).Times(1);
// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\nmock 3\n"),
// _)).Times(1);
//
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, false);
// outputter.bufferMaxSize(2);
//
// // log more lines than the buffer can contain
// outputter.write(kNOTE, "mock 1");
// outputter.write(kNOTE, "mock 2");
// outputter.write(kNOTE, "mock 3");
// outputter.sendBuffer();
// }
//
// TEST(IpcLogOutputterTests, write_underBufferMaxSize_allLinesAreSent)
//{
// MockIpcServer mockServer;
//
// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
//
// EXPECT_CALL(mockServer, hasClients(_)).Times(1);
// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"),
// _)).Times(1);
//
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, false);
// outputter.bufferMaxSize(2);
//
// // log more lines than the buffer can contain
// outputter.write(kNOTE, "mock 1");
// outputter.write(kNOTE, "mock 2");
// outputter.sendBuffer();
// }
//
//// HACK: temporarily disable this intermittently failing unit test.
//// when the build machine is under heavy load, a race condition
//// usually happens.
// #if 0
// TEST(IpcLogOutputterTests, write_overBufferRateLimit_lastLineTruncated)
//{
// MockIpcServer mockServer;
//
// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
//
// EXPECT_CALL(mockServer, hasClients(_)).Times(2);
// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"),
// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock
// 4\nmock 5\n"), _)).Times(1);
//
// IpcLogOutputter outputter(mockServer, false);
// outputter.bufferRateLimit(2, 1); // 1s
//
// // log 1 more line than the buffer can accept in time limit.
// outputter.write(kNOTE, "mock 1");
// outputter.write(kNOTE, "mock 2");
// outputter.write(kNOTE, "mock 3");
//
// outputter.sendBuffer();
//
// // after waiting the time limit send another to make sure
// // we can log after the time limit passes.
// // HACK: sleep causes the unit test to fail intermittently,
// // so lets try 100ms (there must be a better way to solve this)
// ARCH->sleep(2); // 2s
// outputter.write(kNOTE, "mock 4");
// outputter.write(kNOTE, "mock 5");
// outputter.write(kNOTE, "mock 6");
//
// outputter.sendBuffer();
// }
// #endif
//
// TEST(IpcLogOutputterTests, write_underBufferRateLimit_allLinesAreSent)
//{
// MockIpcServer mockServer;
//
// ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true));
//
// EXPECT_CALL(mockServer, hasClients(_)).Times(2);
// EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"),
// _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock
// 3\nmock 4\n"), _)).Times(1);
//
// IpcLogOutputter outputter(mockServer, IpcClientType::Unknown, false);
// outputter.bufferRateLimit(4, 1); // 1s (should be plenty of time)
//
// // log 1 more line than the buffer can accept in time limit.
// outputter.write(kNOTE, "mock 1");
// outputter.write(kNOTE, "mock 2");
// outputter.sendBuffer();
//
// // after waiting the time limit send another to make sure
// // we can log after the time limit passes.
// outputter.write(kNOTE, "mock 3");
// outputter.write(kNOTE, "mock 4");
// outputter.sendBuffer();
// }
#endif // WINAPI_MSWINDOWS

View File

@ -1,22 +0,0 @@
/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2015 - 2016 Symless Ltd.
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#define TEST_ENV
#include "ipc/IpcSettingMessage.h"
#include <gtest/gtest.h>
TEST(IpcSettingMessage, testIpcSettingMessage)
{
const std::string expected_name = "test";
const std::string expected_value = "test_value";
IpcSettingMessage message("test", "test_value");
EXPECT_EQ(expected_name, message.getName());
EXPECT_EQ(expected_value, message.getValue());
}