feat: Implement basic IPC connection between Daemon and GUI
This commit is contained in:
parent
c0094554b1
commit
0d2d9f385d
17 changed files with 219 additions and 218 deletions
|
|
@ -12,23 +12,15 @@
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
|
|
||||||
#include "arch/win32/ArchMiscWindows.h"
|
#include "arch/win32/ArchMiscWindows.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef SYSAPI_UNIX
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
DaemonApp app;
|
|
||||||
return app.run(argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
#elif SYSAPI_WIN32
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
#endif
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
// win32 instance needed for threading, etc.
|
// win32 instance needed for threading, etc.
|
||||||
|
|
@ -45,4 +37,11 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||||
return DaemonApp::exec();
|
return DaemonApp::exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if SYSAPI_WIN32
|
||||||
|
|
||||||
|
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
|
||||||
|
{
|
||||||
|
return main(__argc, __argv);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
#include "gui/constants.h"
|
#include "gui/constants.h"
|
||||||
#include "gui/core/CoreProcess.h"
|
#include "gui/core/CoreProcess.h"
|
||||||
#include "gui/diagnostic.h"
|
#include "gui/diagnostic.h"
|
||||||
|
#include "gui/ipc/DaemonIpcClient.h"
|
||||||
#include "gui/messages.h"
|
#include "gui/messages.h"
|
||||||
#include "gui/string_utils.h"
|
#include "gui/string_utils.h"
|
||||||
#include "gui/style_utils.h"
|
#include "gui/style_utils.h"
|
||||||
|
|
@ -70,6 +71,7 @@ MainWindow::MainWindow(ConfigScopes &configScopes, AppConfig &appConfig)
|
||||||
m_tlsUtility(appConfig),
|
m_tlsUtility(appConfig),
|
||||||
m_trayIcon{new QSystemTrayIcon(this)},
|
m_trayIcon{new QSystemTrayIcon(this)},
|
||||||
m_guiDupeChecker{new QLocalServer(this)},
|
m_guiDupeChecker{new QLocalServer(this)},
|
||||||
|
m_daemonIpcClient{new ipc::DaemonIpcClient(this)},
|
||||||
m_lblSecurityStatus{new QLabel(this)},
|
m_lblSecurityStatus{new QLabel(this)},
|
||||||
m_lblStatus{new QLabel(this)},
|
m_lblStatus{new QLabel(this)},
|
||||||
m_btnFingerprint{new QToolButton(this)},
|
m_btnFingerprint{new QToolButton(this)},
|
||||||
|
|
@ -167,6 +169,8 @@ MainWindow::MainWindow(ConfigScopes &configScopes, AppConfig &appConfig)
|
||||||
regenerateLocalFingerprints();
|
regenerateLocalFingerprints();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_daemonIpcClient->connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,10 @@ namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace deskflow::gui::ipc {
|
||||||
|
class DaemonIpcClient;
|
||||||
|
}
|
||||||
|
|
||||||
class MainWindow : public QMainWindow
|
class MainWindow : public QMainWindow
|
||||||
{
|
{
|
||||||
using CoreMode = deskflow::gui::CoreProcess::Mode;
|
using CoreMode = deskflow::gui::CoreProcess::Mode;
|
||||||
|
|
@ -208,6 +212,7 @@ private:
|
||||||
QStringList m_checkedServers;
|
QStringList m_checkedServers;
|
||||||
QSystemTrayIcon *m_trayIcon = nullptr;
|
QSystemTrayIcon *m_trayIcon = nullptr;
|
||||||
QLocalServer *m_guiDupeChecker = nullptr;
|
QLocalServer *m_guiDupeChecker = nullptr;
|
||||||
|
deskflow::gui::ipc::DaemonIpcClient *m_daemonIpcClient = nullptr;
|
||||||
|
|
||||||
QLabel *m_lblSecurityStatus = nullptr;
|
QLabel *m_lblSecurityStatus = nullptr;
|
||||||
QLabel *m_lblStatus = nullptr;
|
QLabel *m_lblStatus = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Deskflow -- mouse and keyboard sharing utility
|
* Deskflow -- mouse and keyboard sharing utility
|
||||||
* SPDX-FileCopyrightText: (C) 2024 Chris Rizzitello <sithlord48@gmail.com>
|
* SPDX-FileCopyrightText: (C) 2024 Chris Rizzitello <sithlord48@gmail.com>
|
||||||
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd.
|
* SPDX-FileCopyrightText: (C) 2012 - 2025 Symless Ltd.
|
||||||
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
* SPDX-FileCopyrightText: (C) 2002 Chris Schoeneman
|
||||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||||
*/
|
*/
|
||||||
|
|
@ -13,10 +13,11 @@ const auto kAppId = "@CMAKE_PROJECT_NAME@";
|
||||||
const auto kAppDescription = "@CMAKE_PROJECT_DESCRIPTION@";
|
const auto kAppDescription = "@CMAKE_PROJECT_DESCRIPTION@";
|
||||||
const auto kVersion = "@CMAKE_PROJECT_VERSION@";
|
const auto kVersion = "@CMAKE_PROJECT_VERSION@";
|
||||||
const auto kVersionGitSha = "@GIT_SHA_SHORT@";
|
const auto kVersionGitSha = "@GIT_SHA_SHORT@";
|
||||||
|
const auto kDaemonIpcName = "@CMAKE_PROJECT_NAME@-daemon";
|
||||||
|
|
||||||
const auto kCopyright = //
|
const auto kCopyright = //
|
||||||
"Copyright @CMAKE_PROJECT_COPYRIGHT@\n"
|
"Copyright @CMAKE_PROJECT_COPYRIGHT@\n"
|
||||||
"Copyright (C) 2012-2024 Symless Ltd.\n"
|
"Copyright (C) 2012-2025 Symless Ltd.\n"
|
||||||
"Copyright (C) 2009-2012 Nick Bolton\n"
|
"Copyright (C) 2009-2012 Nick Bolton\n"
|
||||||
"Copyright (C) 2002-2009 Chris Schoeneman";
|
"Copyright (C) 2002-2009 Chris Schoeneman";
|
||||||
|
|
||||||
|
|
@ -26,7 +27,6 @@ const auto kDebugBuild = true;
|
||||||
const auto kDebugBuild = false;
|
const auto kDebugBuild = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
const auto kSslDir = "tls";
|
const auto kSslDir = "tls";
|
||||||
const auto kTlsDbSize = 2;
|
const auto kTlsDbSize = 2;
|
||||||
const auto kCertificateFilename = "@CMAKE_PROJECT_NAME@.pem";
|
const auto kCertificateFilename = "@CMAKE_PROJECT_NAME@.pem";
|
||||||
|
|
|
||||||
|
|
@ -145,8 +145,8 @@ add_library(${lib_name} STATIC ${PLATFORM_CODE}
|
||||||
XScreen.h
|
XScreen.h
|
||||||
languages/LanguageManager.cpp
|
languages/LanguageManager.cpp
|
||||||
languages/LanguageManager.h
|
languages/LanguageManager.h
|
||||||
ipc/IpcServer2.cpp
|
ipc/DaemonIpcServer.cpp
|
||||||
ipc/IpcServer2.h
|
ipc/DaemonIpcServer.h
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(Qt6 COMPONENTS Core Network)
|
find_package(Qt6 COMPONENTS Core Network)
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,15 @@
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
#include "base/TMethodEventJob.h"
|
#include "base/TMethodEventJob.h"
|
||||||
#include "base/log_outputters.h"
|
#include "base/log_outputters.h"
|
||||||
#include "common/constants.h"
|
|
||||||
#include "common/ipc.h"
|
#include "common/ipc.h"
|
||||||
#include "deskflow/App.h"
|
#include "deskflow/App.h"
|
||||||
#include "deskflow/ArgParser.h"
|
#include "deskflow/ArgParser.h"
|
||||||
#include "deskflow/ClientArgs.h"
|
#include "deskflow/ClientArgs.h"
|
||||||
#include "deskflow/ServerArgs.h"
|
#include "deskflow/ServerArgs.h"
|
||||||
|
#include "ipc/DaemonIpcServer.h"
|
||||||
#include "ipc/IpcClientProxy.h"
|
#include "ipc/IpcClientProxy.h"
|
||||||
#include "ipc/IpcLogOutputter.h"
|
#include "ipc/IpcLogOutputter.h"
|
||||||
#include "ipc/IpcMessage.h"
|
#include "ipc/IpcMessage.h"
|
||||||
#include "ipc/IpcServer2.h"
|
|
||||||
#include "ipc/IpcSettingMessage.h"
|
#include "ipc/IpcSettingMessage.h"
|
||||||
#include "net/SocketMultiplexer.h"
|
#include "net/SocketMultiplexer.h"
|
||||||
|
|
||||||
|
|
@ -48,6 +47,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
using namespace deskflow::core;
|
||||||
|
|
||||||
const char *const kLogFilename = "deskflow-daemon.log";
|
const char *const kLogFilename = "deskflow-daemon.log";
|
||||||
|
|
||||||
|
|
@ -99,13 +99,8 @@ int winMainLoopStatic(int, const char **)
|
||||||
DaemonApp::DaemonApp(IEventQueue *events, int argc, char **argv)
|
DaemonApp::DaemonApp(IEventQueue *events, int argc, char **argv)
|
||||||
: QCoreApplication(argc, argv),
|
: QCoreApplication(argc, argv),
|
||||||
m_events(events),
|
m_events(events),
|
||||||
m_ipcServer2{new deskflow::ipc::IpcServer2(this)}
|
m_ipcServer{new ipc::DaemonIpcServer(this)}
|
||||||
{
|
{
|
||||||
// HACK: init used to be run, which was the main loop.
|
|
||||||
// now it's used for arg parsing, install/uninstall, etc.
|
|
||||||
if (init(argc, argv) != kExitSuccess) {
|
|
||||||
exit(kExitFailed);
|
|
||||||
}
|
|
||||||
s_instance = this;
|
s_instance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,29 +192,11 @@ void DaemonApp::mainLoop(bool logToFile, bool foreground)
|
||||||
CLOG->insert(m_fileLogOutputter);
|
CLOG->insert(m_fileLogOutputter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create socket multiplexer. this must happen after daemonization
|
|
||||||
// on unix because threads evaporate across a fork().
|
|
||||||
SocketMultiplexer multiplexer;
|
|
||||||
|
|
||||||
// uses event queue, must be created here.
|
|
||||||
m_ipcServer = std::make_unique<IpcServer>(m_events, &multiplexer);
|
|
||||||
|
|
||||||
// send logging to gui via ipc, log system adopts outputter.
|
|
||||||
m_ipcLogOutputter = std::make_unique<IpcLogOutputter>(*m_ipcServer, IpcClientType::GUI, true);
|
|
||||||
CLOG->insert(m_ipcLogOutputter.get());
|
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
m_watchdog = std::make_unique<MSWindowsWatchdog>(false, *m_ipcServer, *m_ipcLogOutputter, foreground);
|
m_watchdog = std::make_unique<MSWindowsWatchdog>(false, foreground);
|
||||||
m_watchdog->setFileLogOutputter(m_fileLogOutputter);
|
m_watchdog->setFileLogOutputter(m_fileLogOutputter);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_events->adoptHandler(
|
|
||||||
m_events->forIpcServer().messageReceived(), m_ipcServer.get(),
|
|
||||||
new TMethodEventJob<DaemonApp>(this, &DaemonApp::handleIpcMessage)
|
|
||||||
);
|
|
||||||
|
|
||||||
m_ipcServer->listen();
|
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
|
|
||||||
// install the platform event queue to handle service stop events.
|
// install the platform event queue to handle service stop events.
|
||||||
|
|
@ -273,113 +250,3 @@ std::string DaemonApp::logFilename()
|
||||||
|
|
||||||
return logFilename;
|
return logFilename;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DaemonApp::handleIpcMessage(const Event &e, void *)
|
|
||||||
{
|
|
||||||
IpcMessage *m = static_cast<IpcMessage *>(e.getDataObject());
|
|
||||||
switch (m->type()) {
|
|
||||||
case IpcMessageType::Command: {
|
|
||||||
IpcCommandMessage *cm = static_cast<IpcCommandMessage *>(m);
|
|
||||||
std::string command = cm->command();
|
|
||||||
|
|
||||||
// if empty quotes, clear.
|
|
||||||
if (command == "\"\"") {
|
|
||||||
command.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!command.empty()) {
|
|
||||||
LOG((CLOG_DEBUG "daemon got new core command"));
|
|
||||||
LOG((CLOG_DEBUG2 "new command, elevate=%d command=%s", cm->elevate(), command.c_str()));
|
|
||||||
|
|
||||||
std::vector<std::string> argsArray;
|
|
||||||
ArgParser::splitCommandString(command, argsArray);
|
|
||||||
ArgParser argParser(NULL);
|
|
||||||
const char **argv = argParser.getArgv(argsArray);
|
|
||||||
int argc = static_cast<int>(argsArray.size());
|
|
||||||
|
|
||||||
if (isServerCommandLine(argsArray)) {
|
|
||||||
auto serverArgs = new deskflow::ServerArgs();
|
|
||||||
argParser.parseServerArgs(*serverArgs, argc, argv);
|
|
||||||
} else {
|
|
||||||
auto clientArgs = new deskflow::ClientArgs();
|
|
||||||
argParser.parseClientArgs(*clientArgs, argc, argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] argv;
|
|
||||||
std::string logLevel(ArgParser::argsBase().m_logFilter);
|
|
||||||
if (!logLevel.empty()) {
|
|
||||||
try {
|
|
||||||
// change log level based on that in the command string
|
|
||||||
// and change to that log level now.
|
|
||||||
ARCH->setting("LogLevel", logLevel);
|
|
||||||
CLOG->setFilter(logLevel.c_str());
|
|
||||||
} catch (XArch &e) {
|
|
||||||
LOG((CLOG_ERR "failed to save LogLevel setting, %s", e.what()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG((CLOG_DEBUG "empty command, elevate=%d", cm->elevate()));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// store command in system settings. this is used when the daemon
|
|
||||||
// next starts.
|
|
||||||
ARCH->setting("Command", command);
|
|
||||||
|
|
||||||
// TODO: it would be nice to store bools/ints...
|
|
||||||
ARCH->setting("Elevate", std::string(cm->elevate() ? "1" : "0"));
|
|
||||||
} catch (XArch &e) {
|
|
||||||
LOG((CLOG_ERR "failed to save settings, %s", e.what()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
|
||||||
// tell the relauncher about the new command. this causes the
|
|
||||||
// relauncher to stop the existing command and start the new
|
|
||||||
// command.
|
|
||||||
m_watchdog->setCommand(command, cm->elevate());
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case IpcMessageType::Hello: {
|
|
||||||
IpcHelloMessage *hm = static_cast<IpcHelloMessage *>(m);
|
|
||||||
std::string type;
|
|
||||||
switch (hm->clientType()) {
|
|
||||||
case IpcClientType::GUI:
|
|
||||||
type = "gui";
|
|
||||||
break;
|
|
||||||
case IpcClientType::Node:
|
|
||||||
type = "node";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
type = "unknown";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG((CLOG_DEBUG "ipc hello, type=%s", type.c_str()));
|
|
||||||
|
|
||||||
// TODO: implement hello back handling in s1 gui and node (server/client).
|
|
||||||
if (hm->clientType() == IpcClientType::GUI) {
|
|
||||||
LOG((CLOG_DEBUG "sending ipc hello back"));
|
|
||||||
IpcHelloBackMessage hbm;
|
|
||||||
m_ipcServer->send(hbm, hm->clientType());
|
|
||||||
}
|
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
|
||||||
std::string watchdogStatus = m_watchdog->isProcessRunning() ? "active" : "idle";
|
|
||||||
LOG((CLOG_INFO "service status: %s", watchdogStatus.c_str()));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
m_ipcLogOutputter->notifyBuffer();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case IpcMessageType::Setting:
|
|
||||||
updateSetting(*m);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
LOG((CLOG_DEBUG "ipc message ignored"));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ipc/IpcServer.h"
|
#include "common/common.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
@ -14,12 +14,13 @@
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
|
||||||
class Event;
|
class Event;
|
||||||
|
class IEventQueue;
|
||||||
class IpcLogOutputter;
|
class IpcLogOutputter;
|
||||||
class FileLogOutputter;
|
class FileLogOutputter;
|
||||||
class QLocalServer;
|
class QLocalServer;
|
||||||
|
|
||||||
namespace deskflow::ipc {
|
namespace deskflow::core::ipc {
|
||||||
class IpcServer2;
|
class DaemonIpcServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
|
|
@ -33,11 +34,11 @@ class DaemonApp : public QCoreApplication
|
||||||
public:
|
public:
|
||||||
DaemonApp(IEventQueue *events, int argc, char **argv);
|
DaemonApp(IEventQueue *events, int argc, char **argv);
|
||||||
~DaemonApp();
|
~DaemonApp();
|
||||||
|
int init(int argc, char **argv);
|
||||||
void startAsync();
|
void startAsync();
|
||||||
void mainLoop(bool logToFile, bool foreground = false);
|
void mainLoop(bool logToFile, bool foreground = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int init(int argc, char **argv);
|
|
||||||
void daemonize();
|
void daemonize();
|
||||||
void foregroundError(const char *message);
|
void foregroundError(const char *message);
|
||||||
std::string logFilename();
|
std::string logFilename();
|
||||||
|
|
@ -51,9 +52,8 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<IpcServer> m_ipcServer;
|
|
||||||
std::unique_ptr<IpcLogOutputter> m_ipcLogOutputter;
|
std::unique_ptr<IpcLogOutputter> m_ipcLogOutputter;
|
||||||
IEventQueue *m_events = nullptr;
|
IEventQueue *m_events = nullptr;
|
||||||
FileLogOutputter *m_fileLogOutputter = nullptr;
|
FileLogOutputter *m_fileLogOutputter = nullptr;
|
||||||
std::unique_ptr<deskflow::ipc::IpcServer2> m_ipcServer2;
|
std::unique_ptr<deskflow::core::ipc::DaemonIpcServer> m_ipcServer;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
69
src/lib/deskflow/ipc/DaemonIpcServer.cpp
Normal file
69
src/lib/deskflow/ipc/DaemonIpcServer.cpp
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Deskflow -- mouse and keyboard sharing utility
|
||||||
|
* SPDX-FileCopyrightText: (C) 2025 Symless Ltd.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DaemonIpcServer.h"
|
||||||
|
|
||||||
|
#include "base/Log.h"
|
||||||
|
#include "common/constants.h"
|
||||||
|
|
||||||
|
#include <QLocalServer>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
|
||||||
|
namespace deskflow::core::ipc {
|
||||||
|
|
||||||
|
DaemonIpcServer::DaemonIpcServer(QObject *parent) : QObject(parent), m_server{new QLocalServer(this)}
|
||||||
|
{
|
||||||
|
// Daemon runs as system, but GUI runs as regular user, so we need to allow world access.
|
||||||
|
m_server->setSocketOptions(QLocalServer::WorldAccessOption);
|
||||||
|
|
||||||
|
connect(m_server, &QLocalServer::newConnection, this, &DaemonIpcServer::handleNewConnection);
|
||||||
|
m_server->removeServer(kDaemonIpcName);
|
||||||
|
if (m_server->listen(kDaemonIpcName)) {
|
||||||
|
LOG_DEBUG("ipc server listening on: %s", kDaemonIpcName);
|
||||||
|
} else {
|
||||||
|
LOG_ERR("ipc server failed to listen on: %s", kDaemonIpcName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DaemonIpcServer::~DaemonIpcServer()
|
||||||
|
{
|
||||||
|
m_server->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonIpcServer::handleNewConnection()
|
||||||
|
{
|
||||||
|
QLocalSocket *clientSocket = m_server->nextPendingConnection();
|
||||||
|
if (!clientSocket) {
|
||||||
|
LOG_ERR("ipc server failed to get new connection");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("ipc server got new connection");
|
||||||
|
|
||||||
|
connect(clientSocket, &QLocalSocket::readyRead, this, [clientSocket]() {
|
||||||
|
LOG_DEBUG("ipc server ready to read data");
|
||||||
|
|
||||||
|
QByteArray data = clientSocket->readAll();
|
||||||
|
if (data.isEmpty()) {
|
||||||
|
LOG_WARN("ipc server got empty message");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString dataStr = QString::fromUtf8(data);
|
||||||
|
if (dataStr.isEmpty()) {
|
||||||
|
LOG_ERR("ipc server failed to convert message to string");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataStr == "hello") {
|
||||||
|
LOG_DEBUG("ipc server got message: %s", data.constData());
|
||||||
|
clientSocket->write("hello");
|
||||||
|
clientSocket->flush();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace deskflow::core::ipc
|
||||||
|
|
@ -10,18 +10,21 @@
|
||||||
|
|
||||||
class QLocalServer;
|
class QLocalServer;
|
||||||
|
|
||||||
namespace deskflow::ipc {
|
namespace deskflow::core::ipc {
|
||||||
|
|
||||||
class IpcServer2 : public QObject
|
class DaemonIpcServer : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IpcServer2(QObject *parent);
|
DaemonIpcServer(QObject *parent);
|
||||||
~IpcServer2();
|
~DaemonIpcServer();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleNewConnection();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLocalServer *m_server;
|
QLocalServer *m_server;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace deskflow::ipc
|
} // namespace deskflow::core::ipc
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
/*
|
|
||||||
* Deskflow -- mouse and keyboard sharing utility
|
|
||||||
* SPDX-FileCopyrightText: (C) 2025 Symless Ltd.
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "IpcServer2.h"
|
|
||||||
|
|
||||||
#include "base/Log.h"
|
|
||||||
|
|
||||||
#include <QLocalServer>
|
|
||||||
|
|
||||||
namespace deskflow::ipc {
|
|
||||||
|
|
||||||
const auto kServerName = QStringLiteral("deskflow-daemon");
|
|
||||||
|
|
||||||
IpcServer2::IpcServer2(QObject *parent) : QObject(parent), m_server{new QLocalServer(this)}
|
|
||||||
{
|
|
||||||
m_server->removeServer(kServerName);
|
|
||||||
m_server->listen(kServerName);
|
|
||||||
LOG_INFO("ipc server listening on %s", kServerName.toStdString().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
IpcServer2::~IpcServer2()
|
|
||||||
{
|
|
||||||
m_server->close();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace deskflow::ipc
|
|
||||||
|
|
@ -69,6 +69,8 @@ add_library(${target} STATIC
|
||||||
ipc/QDataStreamProxy.h
|
ipc/QDataStreamProxy.h
|
||||||
ipc/QIpcClient.cpp
|
ipc/QIpcClient.cpp
|
||||||
ipc/QIpcClient.h
|
ipc/QIpcClient.h
|
||||||
|
ipc/DaemonIpcClient.cpp
|
||||||
|
ipc/DaemonIpcClient.h
|
||||||
proxy/QNetworkAccessManagerProxy.cpp
|
proxy/QNetworkAccessManagerProxy.cpp
|
||||||
proxy/QNetworkAccessManagerProxy.h
|
proxy/QNetworkAccessManagerProxy.h
|
||||||
proxy/QProcessProxy.cpp
|
proxy/QProcessProxy.cpp
|
||||||
|
|
|
||||||
66
src/lib/gui/ipc/DaemonIpcClient.cpp
Normal file
66
src/lib/gui/ipc/DaemonIpcClient.cpp
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Deskflow -- mouse and keyboard sharing utility
|
||||||
|
* SPDX-FileCopyrightText: (C) 2025 Symless Ltd.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DaemonIpcClient.h"
|
||||||
|
|
||||||
|
#include "common/constants.h"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace deskflow::gui::ipc {
|
||||||
|
|
||||||
|
const auto kTimeout = 1000;
|
||||||
|
|
||||||
|
DaemonIpcClient::DaemonIpcClient(QObject *parent) : QObject(parent), socket{new QLocalSocket(this)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DaemonIpcClient::~DaemonIpcClient()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void DaemonIpcClient::connect()
|
||||||
|
{
|
||||||
|
socket->connectToServer(kDaemonIpcName);
|
||||||
|
if (!socket->waitForConnected(kTimeout)) {
|
||||||
|
qCritical() << "ipc client failed to connect to server:" << kDaemonIpcName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket->write("hello");
|
||||||
|
if (!socket->waitForBytesWritten(kTimeout)) {
|
||||||
|
qCritical() << "ipc client failed to write message";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!socket->waitForReadyRead(kTimeout)) {
|
||||||
|
qCritical() << "ipc client failed to read response";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray response = socket->readAll();
|
||||||
|
if (response.isEmpty()) {
|
||||||
|
qCritical() << "ipc client got empty response";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString responseData = QString::fromUtf8(response);
|
||||||
|
if (responseData.isEmpty()) {
|
||||||
|
qCritical() << "ipc client failed to convert response to string";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseData != "hello") {
|
||||||
|
qCritical() << "ipc client got unexpected response: " << responseData;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qInfo() << "ipc client connected to server:" << kDaemonIpcName;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace deskflow::gui::ipc
|
||||||
28
src/lib/gui/ipc/DaemonIpcClient.h
Normal file
28
src/lib/gui/ipc/DaemonIpcClient.h
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Deskflow -- mouse and keyboard sharing utility
|
||||||
|
* SPDX-FileCopyrightText: (C) 2025 Symless Ltd.
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class QLocalSocket;
|
||||||
|
|
||||||
|
namespace deskflow::gui::ipc {
|
||||||
|
|
||||||
|
class DaemonIpcClient : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DaemonIpcClient(QObject *parent = nullptr);
|
||||||
|
~DaemonIpcClient();
|
||||||
|
void connect();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QLocalSocket *socket;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace deskflow::gui::ipc
|
||||||
|
|
@ -113,12 +113,12 @@ DWORD MSWindowsProcess::waitForExit()
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MSWindowsProcess::shutdown(IpcServer &ipcServer, int timeout)
|
void MSWindowsProcess::shutdown(int timeout)
|
||||||
{
|
{
|
||||||
shutdown(m_info.hProcess, m_info.dwProcessId, ipcServer, timeout);
|
shutdown(m_info.hProcess, m_info.dwProcessId, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MSWindowsProcess::shutdown(HANDLE handle, DWORD pid, IpcServer &ipcServer, int timeout)
|
void MSWindowsProcess::shutdown(HANDLE handle, DWORD pid, int timeout)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("shutting down process %d", pid);
|
LOG_DEBUG("shutting down process %d", pid);
|
||||||
|
|
||||||
|
|
@ -129,9 +129,6 @@ void MSWindowsProcess::shutdown(HANDLE handle, DWORD pid, IpcServer &ipcServer,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IpcShutdownMessage shutdown;
|
|
||||||
ipcServer.send(shutdown, IpcClientType::Node);
|
|
||||||
|
|
||||||
// wait for process to exit gracefully.
|
// wait for process to exit gracefully.
|
||||||
double start = ARCH->time();
|
double start = ARCH->time();
|
||||||
while (true) { // NOSONAR -- Multiple breaks necessary
|
while (true) { // NOSONAR -- Multiple breaks necessary
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ipc/IpcServer.h"
|
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
|
|
@ -27,7 +25,7 @@ public:
|
||||||
|
|
||||||
BOOL startInForeground();
|
BOOL startInForeground();
|
||||||
BOOL startAsUser(HANDLE userToken, LPSECURITY_ATTRIBUTES sa);
|
BOOL startAsUser(HANDLE userToken, LPSECURITY_ATTRIBUTES sa);
|
||||||
void shutdown(IpcServer &ipcServer, int timeout = kDefaultShutdownTimeout);
|
void shutdown(int timeout = kDefaultShutdownTimeout);
|
||||||
DWORD waitForExit();
|
DWORD waitForExit();
|
||||||
void createPipes();
|
void createPipes();
|
||||||
std::string readStdOutput();
|
std::string readStdOutput();
|
||||||
|
|
@ -38,7 +36,7 @@ public:
|
||||||
return m_info;
|
return m_info;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void shutdown(HANDLE handle, DWORD pid, IpcServer &ipcServer, int timeout = kDefaultShutdownTimeout);
|
static void shutdown(HANDLE handle, DWORD pid, int timeout = kDefaultShutdownTimeout);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setStartupInfo(STARTUPINFO &si);
|
void setStartupInfo(STARTUPINFO &si);
|
||||||
|
|
|
||||||
|
|
@ -57,17 +57,13 @@ typedef VOID(WINAPI *SendSas)(BOOL asUser);
|
||||||
|
|
||||||
const char g_activeDesktop[] = {"activeDesktop:"};
|
const char g_activeDesktop[] = {"activeDesktop:"};
|
||||||
|
|
||||||
MSWindowsWatchdog::MSWindowsWatchdog(
|
MSWindowsWatchdog::MSWindowsWatchdog(bool autoDetectCommand, bool foreground)
|
||||||
bool autoDetectCommand, IpcServer &ipcServer, IpcLogOutputter &ipcLogOutputter, bool foreground
|
|
||||||
)
|
|
||||||
: m_thread(NULL),
|
: m_thread(NULL),
|
||||||
m_autoDetectCommand(autoDetectCommand),
|
m_autoDetectCommand(autoDetectCommand),
|
||||||
m_monitoring(true),
|
m_monitoring(true),
|
||||||
m_commandChanged(false),
|
m_commandChanged(false),
|
||||||
m_outputWritePipe(nullptr),
|
m_outputWritePipe(nullptr),
|
||||||
m_outputReadPipe(nullptr),
|
m_outputReadPipe(nullptr),
|
||||||
m_ipcServer(ipcServer),
|
|
||||||
m_ipcLogOutputter(ipcLogOutputter),
|
|
||||||
m_elevateProcess(false),
|
m_elevateProcess(false),
|
||||||
m_processFailures(0),
|
m_processFailures(0),
|
||||||
m_processStarted(false),
|
m_processStarted(false),
|
||||||
|
|
@ -265,7 +261,7 @@ void MSWindowsWatchdog::mainLoop(void *)
|
||||||
|
|
||||||
if (m_process != nullptr) {
|
if (m_process != nullptr) {
|
||||||
LOG((CLOG_DEBUG "terminated running process on exit"));
|
LOG((CLOG_DEBUG "terminated running process on exit"));
|
||||||
m_process->shutdown(m_ipcServer);
|
m_process->shutdown();
|
||||||
m_process.reset();
|
m_process.reset();
|
||||||
m_processStarted = false;
|
m_processStarted = false;
|
||||||
}
|
}
|
||||||
|
|
@ -301,7 +297,7 @@ void MSWindowsWatchdog::startProcess()
|
||||||
|
|
||||||
if (m_process != nullptr) {
|
if (m_process != nullptr) {
|
||||||
LOG((CLOG_DEBUG "closing existing process to make way for new one"));
|
LOG((CLOG_DEBUG "closing existing process to make way for new one"));
|
||||||
m_process->shutdown(m_ipcServer);
|
m_process->shutdown();
|
||||||
m_process.reset();
|
m_process.reset();
|
||||||
m_processStarted = false;
|
m_processStarted = false;
|
||||||
}
|
}
|
||||||
|
|
@ -409,8 +405,6 @@ void MSWindowsWatchdog::outputLoop(void *)
|
||||||
} else {
|
} else {
|
||||||
buffer[bytesRead] = '\0';
|
buffer[bytesRead] = '\0';
|
||||||
|
|
||||||
m_ipcLogOutputter.write(kINFO, buffer);
|
|
||||||
|
|
||||||
if (m_fileLogOutputter != NULL) {
|
if (m_fileLogOutputter != NULL) {
|
||||||
m_fileLogOutputter->write(kINFO, buffer);
|
m_fileLogOutputter->write(kINFO, buffer);
|
||||||
}
|
}
|
||||||
|
|
@ -433,7 +427,7 @@ void MSWindowsWatchdog::shutdownExistingProcesses()
|
||||||
LOG_INFO("daemon shutting down existing processes");
|
LOG_INFO("daemon shutting down existing processes");
|
||||||
|
|
||||||
if (m_process != nullptr) {
|
if (m_process != nullptr) {
|
||||||
m_process->shutdown(m_ipcServer);
|
m_process->shutdown();
|
||||||
m_process.reset();
|
m_process.reset();
|
||||||
m_processStarted = false;
|
m_processStarted = false;
|
||||||
}
|
}
|
||||||
|
|
@ -468,7 +462,7 @@ void MSWindowsWatchdog::shutdownExistingProcesses()
|
||||||
_stricmp(entry.szExeFile, "deskflow-core.exe") == 0) {
|
_stricmp(entry.szExeFile, "deskflow-core.exe") == 0) {
|
||||||
|
|
||||||
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
|
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
|
||||||
deskflow::platform::MSWindowsProcess::shutdown(handle, entry.th32ProcessID, m_ipcServer);
|
deskflow::platform::MSWindowsProcess::shutdown(handle, entry.th32ProcessID);
|
||||||
CloseHandle(handle);
|
CloseHandle(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ class FileLogOutputter;
|
||||||
class MSWindowsWatchdog
|
class MSWindowsWatchdog
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MSWindowsWatchdog(bool autoDetectCommand, IpcServer &ipcServer, IpcLogOutputter &ipcLogOutputter, bool foreground);
|
MSWindowsWatchdog(bool autoDetectCommand, bool foreground);
|
||||||
virtual ~MSWindowsWatchdog();
|
virtual ~MSWindowsWatchdog();
|
||||||
|
|
||||||
void startAsync();
|
void startAsync();
|
||||||
|
|
@ -65,8 +65,6 @@ private:
|
||||||
HANDLE m_outputWritePipe;
|
HANDLE m_outputWritePipe;
|
||||||
HANDLE m_outputReadPipe;
|
HANDLE m_outputReadPipe;
|
||||||
Thread *m_outputThread;
|
Thread *m_outputThread;
|
||||||
IpcServer &m_ipcServer;
|
|
||||||
IpcLogOutputter &m_ipcLogOutputter;
|
|
||||||
bool m_elevateProcess;
|
bool m_elevateProcess;
|
||||||
MSWindowsSession m_session;
|
MSWindowsSession m_session;
|
||||||
int m_processFailures;
|
int m_processFailures;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue