diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d743f3d..a154ba06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -322,6 +322,6 @@ add_subdirectory (src) if (SYNERGY_TIDY) set_property (TARGET synergys synergyc synergy-core - arch base client common core io ipc mt net platform server shared + arch base client common core io mt net platform server shared PROPERTY CXX_CLANG_TIDY "${DO_CLANG_TIDY}") endif() diff --git a/src/cmd/core/CMakeLists.txt b/src/cmd/core/CMakeLists.txt index b9aaa789..5a7663f6 100644 --- a/src/cmd/core/CMakeLists.txt +++ b/src/cmd/core/CMakeLists.txt @@ -15,7 +15,7 @@ add_executable(synergy-core main.cpp) target_link_libraries(synergy-core - arch base client common io mt net ipc platform server core ${libs}) + arch base client common io mt net platform server core ${libs}) if (SYNERGY_CORE_INSTALL) if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") diff --git a/src/cmd/synergyc/CMakeLists.txt b/src/cmd/synergyc/CMakeLists.txt index 9cc6ab67..9926a902 100644 --- a/src/cmd/synergyc/CMakeLists.txt +++ b/src/cmd/synergyc/CMakeLists.txt @@ -39,4 +39,4 @@ endif() add_executable(synergyc ${sources}) target_link_libraries(synergyc - arch base client common io mt net ipc platform server core ${libs}) + arch base client common io mt net platform server core ${libs}) diff --git a/src/cmd/synergys/CMakeLists.txt b/src/cmd/synergys/CMakeLists.txt index e03f35da..8f699068 100644 --- a/src/cmd/synergys/CMakeLists.txt +++ b/src/cmd/synergys/CMakeLists.txt @@ -36,4 +36,4 @@ endif() add_executable(synergys ${sources}) target_link_libraries(synergys - arch base client common io mt net ipc platform server core ${libs}) + arch base client common io mt net platform server core ${libs}) diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 23189121..93fa956c 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -20,7 +20,6 @@ add_subdirectory(base) add_subdirectory(client) add_subdirectory(common) add_subdirectory(io) -add_subdirectory(ipc) add_subdirectory(mt) add_subdirectory(net) add_subdirectory(platform) diff --git a/src/lib/base/EventQueue.cpp b/src/lib/base/EventQueue.cpp index 14443769..a85d0ae6 100644 --- a/src/lib/base/EventQueue.cpp +++ b/src/lib/base/EventQueue.cpp @@ -30,10 +30,6 @@ 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) @@ -68,10 +64,6 @@ EventQueue::EventQueue() : m_nextType(Event::kLast), m_typesForClient(nullptr), m_typesForIStream(nullptr), - m_typesForIpcClient(nullptr), - m_typesForIpcClientProxy(nullptr), - m_typesForIpcServer(nullptr), - m_typesForIpcServerProxy(nullptr), m_typesForIDataSocket(nullptr), m_typesForIListenSocket(nullptr), m_typesForISocket(nullptr), diff --git a/src/lib/base/EventQueue.h b/src/lib/base/EventQueue.h index 8b85f46a..c0f282bc 100644 --- a/src/lib/base/EventQueue.h +++ b/src/lib/base/EventQueue.h @@ -141,10 +141,6 @@ public: // ClientEvents& forClient(); IStreamEvents& forIStream(); - IpcClientEvents& forIpcClient(); - IpcClientProxyEvents& forIpcClientProxy(); - IpcServerEvents& forIpcServer(); - IpcServerProxyEvents& forIpcServerProxy(); IDataSocketEvents& forIDataSocket(); IListenSocketEvents& forIListenSocket(); ISocketEvents& forISocket(); @@ -163,10 +159,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; diff --git a/src/lib/base/EventTypes.cpp b/src/lib/base/EventTypes.cpp index 38bfc5da..45eee8a1 100644 --- a/src/lib/base/EventTypes.cpp +++ b/src/lib/base/EventTypes.cpp @@ -57,26 +57,6 @@ REGISTER_EVENT(IStream, outputError) REGISTER_EVENT(IStream, inputShutdown) REGISTER_EVENT(IStream, outputShutdown) -// -// IpcClient -// - -REGISTER_EVENT(IpcClient, connected) -REGISTER_EVENT(IpcClient, messageReceived) - -// -// IpcClientProxy -// - -REGISTER_EVENT(IpcClientProxy, messageReceived) -REGISTER_EVENT(IpcClientProxy, disconnected) - -// -// IpcServerProxy -// - -REGISTER_EVENT(IpcServerProxy, messageReceived) - // // IDataSocket // @@ -178,13 +158,6 @@ REGISTER_EVENT(IScreen, shapeChanged) REGISTER_EVENT(IScreen, suspend) REGISTER_EVENT(IScreen, resume) -// -// IpcServer -// - -REGISTER_EVENT(IpcServer, clientConnected) -REGISTER_EVENT(IpcServer, messageReceived) - // // Clipboard // diff --git a/src/lib/base/EventTypes.h b/src/lib/base/EventTypes.h index 18b0939f..2c58b392 100644 --- a/src/lib/base/EventTypes.h +++ b/src/lib/base/EventTypes.h @@ -143,89 +143,6 @@ private: Event::Type m_outputShutdown; }; -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: IDataSocketEvents() : diff --git a/src/lib/base/IEventQueue.h b/src/lib/base/IEventQueue.h index 82b27108..7844e53f 100644 --- a/src/lib/base/IEventQueue.h +++ b/src/lib/base/IEventQueue.h @@ -32,10 +32,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; @@ -230,10 +226,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; diff --git a/src/lib/core/App.cpp b/src/lib/core/App.cpp index beeac81b..aa5db401 100644 --- a/src/lib/core/App.cpp +++ b/src/lib/core/App.cpp @@ -29,9 +29,6 @@ #include "core/ArgsBase.h" #include "core/XSynergy.h" #include "core/protocol_types.h" -#include "ipc/Ipc.h" -#include "ipc/IpcMessage.h" -#include "ipc/IpcServerProxy.h" #include #include @@ -64,7 +61,6 @@ App::App(IEventQueue* events, ArgsBase* args) : m_args(args), m_fileLog(nullptr), m_appUtil(events), - m_ipcClient(nullptr), m_socketMultiplexer(nullptr) { assert(s_instance == nullptr); @@ -211,35 +207,6 @@ 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(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* /*unused*/) -{ - auto* m = dynamic_cast(e.getDataObject()); - if (m->type() == kIpcShutdown) { - LOG((CLOG_INFO "got ipc shutdown message")); - m_events->addEvent(Event(Event::kQuit)); - } -} - void App::runEventsLoop(void* /*unused*/) { diff --git a/src/lib/core/App.h b/src/lib/core/App.h index 595e1cd0..d33d8291 100644 --- a/src/lib/core/App.h +++ b/src/lib/core/App.h @@ -18,7 +18,6 @@ #pragma once -#include "ipc/IpcClient.h" #include "core/IApp.h" #include "base/String.h" #include "base/Log.h" @@ -95,12 +94,7 @@ public: void setEvents(EventQueue& events) { m_events = &events; } -private: - void handleIpcMessage(const Event&, void*); - protected: - void initIpcClient(); - void cleanupIpcClient(); void runEventsLoop(void*); bool m_suspended; @@ -111,7 +105,6 @@ private: static App* s_instance; FileLogOutputter* m_fileLog; ARCH_APP_UTIL m_appUtil; - IpcClient* m_ipcClient; SocketMultiplexer* m_socketMultiplexer; }; diff --git a/src/lib/core/ArgParser.cpp b/src/lib/core/ArgParser.cpp index 217474cd..25ad47d7 100644 --- a/src/lib/core/ArgParser.cpp +++ b/src/lib/core/ArgParser.cpp @@ -252,7 +252,7 @@ ArgParser::parseGenericArgs(int argc, const char* const* argv, int& i) argsBase().m_shouldExit = true; } else if (isArg(i, argc, argv, nullptr, "--ipc")) { - argsBase().m_enableIpc = true; + LOG((CLOG_INFO "ignoring --ipc. The old IPC was removed.")); } else if (isArg(i, argc, argv, nullptr, "--server")) { // supress error when --server is used diff --git a/src/lib/core/ArgsBase.cpp b/src/lib/core/ArgsBase.cpp index 083c30af..81b08f6c 100644 --- a/src/lib/core/ArgsBase.cpp +++ b/src/lib/core/ArgsBase.cpp @@ -38,7 +38,6 @@ m_pname(nullptr), m_logFilter(nullptr), m_logFile(nullptr), m_display(nullptr), -m_enableIpc(false), m_enableDragDrop(false), m_shouldExit(false), m_profileDirectory(""), diff --git a/src/lib/core/ArgsBase.h b/src/lib/core/ArgsBase.h index f8ece829..394ed7e4 100644 --- a/src/lib/core/ArgsBase.h +++ b/src/lib/core/ArgsBase.h @@ -35,7 +35,6 @@ public: const char* m_logFile; const char* m_display; String m_name; - bool m_enableIpc; bool m_enableDragDrop; #if SYSAPI_WIN32 bool m_debugServiceWait; diff --git a/src/lib/core/CMakeLists.txt b/src/lib/core/CMakeLists.txt index 2c3fd32a..c3393b14 100644 --- a/src/lib/core/CMakeLists.txt +++ b/src/lib/core/CMakeLists.txt @@ -36,5 +36,5 @@ endif() add_library(core STATIC ${sources}) if (UNIX) - target_link_libraries(core arch client ipc net base platform mt server) + target_link_libraries(core arch client net base platform mt server) endif() diff --git a/src/lib/core/ClientApp.cpp b/src/lib/core/ClientApp.cpp index d34cfea2..d206456b 100644 --- a/src/lib/core/ClientApp.cpp +++ b/src/lib/core/ClientApp.cpp @@ -453,12 +453,6 @@ 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. @@ -489,10 +483,6 @@ ClientApp::mainLoop() updateStatus(); LOG((CLOG_NOTE "stopped client")); - if (argsBase().m_enableIpc) { - cleanupIpcClient(); - } - return kExitSuccess; } diff --git a/src/lib/core/DaemonApp.cpp b/src/lib/core/DaemonApp.cpp index 701537d5..5d9e8076 100644 --- a/src/lib/core/DaemonApp.cpp +++ b/src/lib/core/DaemonApp.cpp @@ -32,9 +32,6 @@ #include "core/ArgParser.h" #include "core/ClientArgs.h" #include "core/ServerArgs.h" -#include "ipc/IpcClientProxy.h" -#include "ipc/IpcLogOutputter.h" -#include "ipc/IpcMessage.h" #include "net/SocketMultiplexer.h" #if SYSAPI_WIN32 @@ -44,7 +41,6 @@ #include "core/Screen.h" #include "platform/MSWindowsScreen.h" #include "platform/MSWindowsDebugOutputter.h" -#include "platform/MSWindowsWatchdog.h" #include "platform/MSWindowsEventQueueBuffer.h" #define WIN32_LEAN_AND_MEAN @@ -82,8 +78,6 @@ winMainLoopStatic(int, const char**) #endif DaemonApp::DaemonApp() : - m_ipcServer(nullptr), - m_ipcLogOutputter(nullptr), #if SYSAPI_WIN32 m_watchdog(nullptr), #endif @@ -206,53 +200,8 @@ DaemonApp::mainLoop(bool logToFile) // 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 = new IpcServer(m_events, &multiplexer); - - // send logging to gui via ipc, log system adopts outputter. - m_ipcLogOutputter = new IpcLogOutputter(*m_ipcServer, kIpcClientGui, true); - CLOG->insert(m_ipcLogOutputter); - -#if SYSAPI_WIN32 - m_watchdog = new MSWindowsWatchdog(false, *m_ipcServer, *m_ipcLogOutputter); - m_watchdog->setFileLogOutputter(m_fileLogOutputter); -#endif - - m_events->adoptHandler( - m_events->forIpcServer().messageReceived(), m_ipcServer, - new TMethodEventJob(this, &DaemonApp::handleIpcMessage)); - - m_ipcServer->listen(); - -#if SYSAPI_WIN32 - - // install the platform event queue to handle service stop events. - m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events)); - - String command = ARCH->setting("Command"); - bool elevate = ARCH->setting("Elevate") == "1"; - if (command != "") { - LOG((CLOG_INFO "using last known command: %s", command.c_str())); - m_watchdog->setCommand(command, elevate); - } - - m_watchdog->startAsync(); -#endif m_events->loop(); -#if SYSAPI_WIN32 - m_watchdog->stop(); - delete m_watchdog; -#endif - - m_events->removeHandler( - m_events->forIpcServer().messageReceived(), m_ipcServer); - - CLOG->remove(m_ipcLogOutputter); - delete m_ipcLogOutputter; - delete m_ipcServer; - DAEMON_RUNNING(false); } catch (std::exception& e) { @@ -286,117 +235,3 @@ DaemonApp::logFilename() return logFilename; } - -void -DaemonApp::handleIpcMessage(const Event& e, void* /*unused*/) -{ - auto* m = dynamic_cast(e.getDataObject()); - switch (m->type()) { - case kIpcCommand: { - auto* cm = dynamic_cast(m); - String command = cm->command(); - - // if empty quotes, clear. - if (command == "\"\"") { - command.clear(); - } - - if (!command.empty()) { - LOG((CLOG_DEBUG "new command, elevate=%d command=%s", cm->elevate(), command.c_str())); - - std::vector argsArray; - ArgParser::splitCommandString(command, argsArray); - ArgParser argParser(nullptr); - const char** argv = argParser.getArgv(argsArray); - ServerArgs serverArgs; - ClientArgs clientArgs; - auto argc = static_cast(argsArray.size()); - bool server = argsArray[0].find("synergys") != String::npos; - ArgsBase* argBase = nullptr; - - if (server) { - argParser.parseServerArgs(serverArgs, argc, argv); - argBase = &serverArgs; - } - else { - argParser.parseClientArgs(clientArgs, argc, argv); - argBase = &clientArgs; - } - - delete[] argv; - - String logLevel(argBase->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())); - } - } - -#if SYSAPI_WIN32 - String logFilename; - if (argBase->m_logFile != NULL) { - logFilename = String(argBase->m_logFile); - ARCH->setting("LogFilename", logFilename); - m_watchdog->setFileLogOutputter(m_fileLogOutputter); - command = ArgParser::assembleCommand(argsArray, "--log", 1); - LOG((CLOG_DEBUG "removed log file argument and filename %s from command ", logFilename.c_str())); - LOG((CLOG_DEBUG "new command, elevate=%d command=%s", cm->elevate(), command.c_str())); - } - else { - m_watchdog->setFileLogOutputter(NULL); - } - - m_fileLogOutputter->setLogFilename(logFilename.c_str()); -#endif - } - 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(andrew): it would be nice to store bools/ints... - ARCH->setting("Elevate", 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 kIpcHello: - auto* hm = dynamic_cast(m); - String type; - switch (hm->clientType()) { - case kIpcClientGui: type = "gui"; break; - case kIpcClientNode: type = "node"; break; - default: type = "unknown"; break; - } - - LOG((CLOG_DEBUG "ipc hello, type=%s", type.c_str())); - -#if SYSAPI_WIN32 - String watchdogStatus = m_watchdog->isProcessActive() ? "ok" : "error"; - LOG((CLOG_INFO "watchdog status: %s", watchdogStatus.c_str())); -#endif - - m_ipcLogOutputter->notifyBuffer(); - break; - } -} diff --git a/src/lib/core/DaemonApp.h b/src/lib/core/DaemonApp.h index 511c6d53..091bd410 100644 --- a/src/lib/core/DaemonApp.h +++ b/src/lib/core/DaemonApp.h @@ -19,18 +19,17 @@ #pragma once #include "arch/Arch.h" -#include "ipc/IpcServer.h" - #include class Event; -class IpcLogOutputter; class FileLogOutputter; #if SYSAPI_WIN32 class MSWindowsWatchdog; #endif +class IEventQueue; + class DaemonApp { public: @@ -43,7 +42,6 @@ private: void daemonize(); void foregroundError(const char* message); std::string logFilename(); - void handleIpcMessage(const Event&, void*); public: static DaemonApp* s_instance; @@ -53,8 +51,6 @@ public: #endif private: - IpcServer* m_ipcServer; - IpcLogOutputter* m_ipcLogOutputter; IEventQueue* m_events; FileLogOutputter* m_fileLogOutputter; }; diff --git a/src/lib/core/ServerApp.cpp b/src/lib/core/ServerApp.cpp index af09e950..35b5794d 100644 --- a/src/lib/core/ServerApp.cpp +++ b/src/lib/core/ServerApp.cpp @@ -704,12 +704,6 @@ 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, nullptr); m_events->adoptHandler(m_events->forServerApp().reloadConfig(), @@ -762,10 +756,6 @@ ServerApp::mainLoop() updateStatus(); LOG((CLOG_NOTE "stopped server")); - if (argsBase().m_enableIpc) { - cleanupIpcClient(); - } - return kExitSuccess; } diff --git a/src/lib/ipc/CMakeLists.txt b/src/lib/ipc/CMakeLists.txt deleted file mode 100644 index 0759ce7c..00000000 --- a/src/lib/ipc/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -# synergy -- mouse and keyboard sharing utility -# Copyright (C) 2012-2016 Symless Ltd. -# Copyright (C) 2009 Nick Bolton -# -# This package is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# found in the file LICENSE that should have accompanied this file. -# -# This package is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -file(GLOB headers "*.h") -file(GLOB sources "*.cpp") - -if (SYNERGY_ADD_HEADERS) - list(APPEND sources ${headers}) -endif() - -add_library(ipc STATIC ${sources}) - -if (UNIX) - target_link_libraries(ipc arch base common mt io net core) -endif() diff --git a/src/lib/ipc/Ipc.cpp b/src/lib/ipc/Ipc.cpp deleted file mode 100644 index c0667714..00000000 --- a/src/lib/ipc/Ipc.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "ipc/Ipc.h" - -const char* kIpcMsgHello = "IHEL%1i"; -const char* kIpcMsgLogLine = "ILOG%s"; -const char* kIpcMsgCommand = "ICMD%s%1i"; -const char* kIpcMsgShutdown = "ISDN"; diff --git a/src/lib/ipc/Ipc.h b/src/lib/ipc/Ipc.h deleted file mode 100644 index b4a4e201..00000000 --- a/src/lib/ipc/Ipc.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#define IPC_HOST "127.0.0.1" -#define IPC_PORT 24801 - -enum EIpcMessage { - kIpcHello, - kIpcLogLine, - kIpcCommand, - kIpcShutdown, -}; - -enum EIpcClientType { - kIpcClientUnknown, - kIpcClientGui, - kIpcClientNode, -}; - -// handshake: node/gui -> daemon -// $1 = type, the client identifies it's self as gui or node (synergyc/s). -extern const char* kIpcMsgHello; - -// log line: daemon -> gui -// $1 = aggregate log lines collected from synergys/c or the daemon itself. -extern const char* kIpcMsgLogLine; - -// command: gui -> daemon -// $1 = command; the command for the daemon to launch, typically the full -// path to synergys/c. $2 = true when process must be elevated on ms windows. -extern const char* kIpcMsgCommand; - -// shutdown: daemon -> node -// the daemon tells synergys/c to shut down gracefully. -extern const char* kIpcMsgShutdown; diff --git a/src/lib/ipc/IpcClient.cpp b/src/lib/ipc/IpcClient.cpp deleted file mode 100644 index ffe8358e..00000000 --- a/src/lib/ipc/IpcClient.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "ipc/IpcClient.h" -#include "base/TMethodEventJob.h" -#include "ipc/Ipc.h" -#include "ipc/IpcMessage.h" -#include "ipc/IpcServerProxy.h" - -// -// IpcClient -// - -IpcClient::IpcClient(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : - m_serverAddress(NetworkAddress(IPC_HOST, IPC_PORT)), - m_socket(events, socketMultiplexer), - m_server(nullptr), - m_events(events) -{ - init(); -} - -IpcClient::IpcClient(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port) : - m_serverAddress(NetworkAddress(IPC_HOST, port)), - m_socket(events, socketMultiplexer), - m_server(nullptr), - m_events(events) -{ - init(); -} - -void -IpcClient::init() -{ - m_serverAddress.resolve(); -} - -IpcClient::~IpcClient() -= default; - -void -IpcClient::connect() -{ - m_events->adoptHandler( - m_events->forIDataSocket().connected(), m_socket.getEventTarget(), - new TMethodEventJob( - 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( - 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& /*unused*/, void* /*unused*/) -{ - m_events->addEvent(Event( - m_events->forIpcClient().connected(), this, m_server, Event::kDontFreeData)); - - IpcHelloMessage message(kIpcClientNode); - send(message); -} - -void -IpcClient::handleMessageReceived(const Event& e, void* /*unused*/) -{ - Event event(m_events->forIpcClient().messageReceived(), this); - event.setDataObject(e.getDataObject()); - m_events->addEvent(event); -} diff --git a/src/lib/ipc/IpcClient.h b/src/lib/ipc/IpcClient.h deleted file mode 100644 index fb31a26d..00000000 --- a/src/lib/ipc/IpcClient.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include "net/NetworkAddress.h" -#include "net/TCPSocket.h" -#include "base/EventTypes.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; -}; diff --git a/src/lib/ipc/IpcClientProxy.cpp b/src/lib/ipc/IpcClientProxy.cpp deleted file mode 100644 index 6e18209a..00000000 --- a/src/lib/ipc/IpcClientProxy.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "ipc/IpcClientProxy.h" - -#include "arch/Arch.h" -#include "base/Log.h" -#include "base/TMethodEventJob.h" -#include "core/ProtocolUtil.h" -#include "io/IStream.h" -#include "ipc/Ipc.h" -#include "ipc/IpcMessage.h" - -// -// IpcClientProxy -// - -IpcClientProxy::IpcClientProxy(synergy::IStream& stream, IEventQueue* events) : - m_stream(stream), - m_clientType(kIpcClientUnknown), - m_disconnecting(false), - m_readMutex(ARCH->newMutex()), - m_writeMutex(ARCH->newMutex()), - m_events(events) -{ - m_events->adoptHandler( - m_events->forIStream().inputReady(), stream.getEventTarget(), - new TMethodEventJob( - this, &IpcClientProxy::handleData)); - - m_events->adoptHandler( - m_events->forIStream().outputError(), stream.getEventTarget(), - new TMethodEventJob( - this, &IpcClientProxy::handleWriteError)); - - m_events->adoptHandler( - m_events->forIStream().inputShutdown(), stream.getEventTarget(), - new TMethodEventJob( - this, &IpcClientProxy::handleDisconnect)); - - m_events->adoptHandler( - m_events->forIStream().outputShutdown(), stream.getEventTarget(), - new TMethodEventJob( - 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& /*unused*/, void* /*unused*/) -{ - disconnect(); - LOG((CLOG_DEBUG "ipc client disconnected")); -} - -void -IpcClientProxy::handleWriteError(const Event& /*unused*/, void* /*unused*/) -{ - disconnect(); - LOG((CLOG_DEBUG "ipc client write error")); -} - -void -IpcClientProxy::handleData(const Event& /*unused*/, void* /*unused*/) -{ - // 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 code[4]; - UInt32 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 { - 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, nullptr, 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 kIpcLogLine: { - const auto& llm = dynamic_cast(message); - const String logLine = llm.logLine(); - ProtocolUtil::writef(&m_stream, kIpcMsgLogLine, &logLine); - break; - } - - case kIpcShutdown: - ProtocolUtil::writef(&m_stream, kIpcMsgShutdown); - break; - - default: - LOG((CLOG_ERR "ipc message not supported: %d", message.type())); - break; - } -} - -IpcHelloMessage* -IpcClientProxy::parseHello() -{ - UInt8 type; - ProtocolUtil::readf(&m_stream, kIpcMsgHello + 4, &type); - - m_clientType = static_cast(type); - - // must be deleted by event handler. - return new IpcHelloMessage(m_clientType); -} - -IpcCommandMessage* -IpcClientProxy::parseCommand() -{ - String command; - UInt8 elevate; - ProtocolUtil::readf(&m_stream, kIpcMsgCommand + 4, &command, &elevate); - - // must be deleted by event handler. - return new IpcCommandMessage(command, elevate != 0); -} - -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)); -} diff --git a/src/lib/ipc/IpcClientProxy.h b/src/lib/ipc/IpcClientProxy.h deleted file mode 100644 index d9a22e13..00000000 --- a/src/lib/ipc/IpcClientProxy.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include "ipc/Ipc.h" -#include "arch/IArchMultithread.h" -#include "base/EventTypes.h" -#include "base/Event.h" - -namespace synergy { class IStream; } -class IpcMessage; -class IpcCommandMessage; -class IpcHelloMessage; -class IEventQueue; - -class IpcClientProxy { - friend class IpcServer; - -public: - IpcClientProxy(synergy::IStream& stream, IEventQueue* events); - virtual ~IpcClientProxy(); - -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(); - void disconnect(); - -private: - synergy::IStream& m_stream; - EIpcClientType m_clientType; - bool m_disconnecting; - ArchMutex m_readMutex; - ArchMutex m_writeMutex; - IEventQueue* m_events; -}; diff --git a/src/lib/ipc/IpcLogOutputter.cpp b/src/lib/ipc/IpcLogOutputter.cpp deleted file mode 100644 index cbf749d5..00000000 --- a/src/lib/ipc/IpcLogOutputter.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#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 "ipc/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, EIpcClientType 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) { - m_bufferThread = new Thread(new TMethodJob( - this, &IpcLogOutputter::bufferThread)); - } -} - -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 /*level*/, 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 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* /*unused*/) -{ - 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); -} - -String -IpcLogOutputter::getChunk(size_t count) -{ - ArchMutexLock lock(m_bufferMutex); - - if (m_buffer.size() < count) { - count = m_buffer.size(); - } - - 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, kIpcClientGui); - m_sending = false; -} - -void -IpcLogOutputter::bufferMaxSize(UInt16 bufferMaxSize) -{ - m_bufferMaxSize = bufferMaxSize; -} - -UInt16 -IpcLogOutputter::bufferMaxSize() const -{ - return m_bufferMaxSize; -} - -void -IpcLogOutputter::bufferRateLimit(UInt16 writeLimit, double timeLimit) -{ - m_bufferRateWriteLimit = writeLimit; - m_bufferRateTimeLimit = timeLimit; -} diff --git a/src/lib/ipc/IpcLogOutputter.h b/src/lib/ipc/IpcLogOutputter.h deleted file mode 100644 index dad845d1..00000000 --- a/src/lib/ipc/IpcLogOutputter.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include "arch/Arch.h" -#include "arch/IArchMultithread.h" -#include "base/ILogOutputter.h" -#include "ipc/Ipc.h" - -#include - -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, EIpcClientType clientType, bool useThread); - 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* text); - - //! @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 bufferMaxSize); - - //! Set the rate limit - /*! - Set the maximum number of \p writeRate for every \p timeRate in seconds. - */ - void bufferRateLimit(UInt16 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 bufferMaxSize() const; - - //@} - -private: - void init(); - void bufferThread(void*); - String getChunk(size_t count); - void appendBuffer(const String& text); - bool isRunning(); - -private: - typedef std::deque Buffer; - - 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 m_bufferMaxSize; - UInt16 m_bufferRateWriteLimit; - double m_bufferRateTimeLimit; - UInt16 m_bufferWriteCount; - double m_bufferRateStart; - EIpcClientType m_clientType; - ArchMutex m_runningMutex; -}; diff --git a/src/lib/ipc/IpcMessage.cpp b/src/lib/ipc/IpcMessage.cpp deleted file mode 100644 index 4bc18824..00000000 --- a/src/lib/ipc/IpcMessage.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "ipc/IpcMessage.h" - -#include -#include "ipc/Ipc.h" - -IpcMessage::IpcMessage(UInt8 type) : - m_type(type) -{ -} - -IpcMessage::~IpcMessage() -= default; - -IpcHelloMessage::IpcHelloMessage(EIpcClientType clientType) : - IpcMessage(kIpcHello), - m_clientType(clientType) -{ -} - -IpcHelloMessage::~IpcHelloMessage() -= default; - -IpcShutdownMessage::IpcShutdownMessage() : -IpcMessage(kIpcShutdown) -{ -} - -IpcShutdownMessage::~IpcShutdownMessage() -= default; - -IpcLogLineMessage::IpcLogLineMessage(String logLine) : -IpcMessage(kIpcLogLine), -m_logLine(std::move(logLine)) -{ -} - -IpcLogLineMessage::~IpcLogLineMessage() -= default; - -IpcCommandMessage::IpcCommandMessage(String command, bool elevate) : -IpcMessage(kIpcCommand), -m_command(std::move(command)), -m_elevate(elevate) -{ -} - -IpcCommandMessage::~IpcCommandMessage() -= default; diff --git a/src/lib/ipc/IpcMessage.h b/src/lib/ipc/IpcMessage.h deleted file mode 100644 index ec8e9a11..00000000 --- a/src/lib/ipc/IpcMessage.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include "ipc/Ipc.h" -#include "base/EventTypes.h" -#include "base/String.h" -#include "base/Event.h" - -class IpcMessage : public EventData { -public: - virtual ~IpcMessage(); - - //! Gets the message type ID. - UInt8 type() const { return m_type; } - -protected: - IpcMessage(UInt8 type); - -private: - UInt8 m_type; -}; - -class IpcHelloMessage : public IpcMessage { -public: - IpcHelloMessage(EIpcClientType clientType); - virtual ~IpcHelloMessage(); - - //! Gets the message type ID. - EIpcClientType clientType() const { return m_clientType; } - -private: - EIpcClientType m_clientType; -}; - -class IpcShutdownMessage : public IpcMessage { -public: - IpcShutdownMessage(); - virtual ~IpcShutdownMessage(); -}; - - -class IpcLogLineMessage : public IpcMessage { -public: - IpcLogLineMessage(String logLine); - virtual ~IpcLogLineMessage(); - - //! Gets the log line. - String logLine() const { return m_logLine; } - -private: - String m_logLine; -}; - -class IpcCommandMessage : public IpcMessage { -public: - IpcCommandMessage(String command, bool elevate); - virtual ~IpcCommandMessage(); - - //! Gets the command. - 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: - String m_command; - bool m_elevate; -}; diff --git a/src/lib/ipc/IpcServer.cpp b/src/lib/ipc/IpcServer.cpp deleted file mode 100644 index b92a0ef3..00000000 --- a/src/lib/ipc/IpcServer.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "ipc/IpcServer.h" - -#include "base/Event.h" -#include "base/IEventQueue.h" -#include "base/Log.h" -#include "base/TMethodEventJob.h" -#include "io/IStream.h" -#include "ipc/Ipc.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(IPC_HOST, IPC_PORT)) -{ - init(); -} - -IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port) : - m_mock(false), - m_events(events), - m_socketMultiplexer(socketMultiplexer), - m_address(NetworkAddress(IPC_HOST, port)) -{ - init(); -} - -void -IpcServer::init() -{ - m_socket = new TCPListenSocket(m_events, m_socketMultiplexer); - - m_clientsMutex = ARCH->newMutex(); - m_address.resolve(); - - m_events->adoptHandler( - m_events->forIListenSocket().connecting(), m_socket, - new TMethodEventJob( - this, &IpcServer::handleClientConnecting)); -} - -IpcServer::~IpcServer() -{ - if (m_mock) { - return; - } - - - 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& /*unused*/, void* /*unused*/) -{ - synergy::IStream* stream = m_socket->accept(); - if (stream == nullptr) { - return; - } - - LOG((CLOG_DEBUG "accepted ipc client connection")); - - ARCH->lockMutex(m_clientsMutex); - auto* 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( - this, &IpcServer::handleClientDisconnected)); - - m_events->adoptHandler( - m_events->forIpcClientProxy().messageReceived(), proxy, - new TMethodEventJob( - this, &IpcServer::handleMessageReceived)); - - m_events->addEvent(Event( - m_events->forIpcServer().clientConnected(), this, proxy, Event::kDontFreeData)); -} - -void -IpcServer::handleClientDisconnected(const Event& e, void* /*unused*/) -{ - auto* proxy = static_cast(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* /*unused*/) -{ - 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(EIpcClientType 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, EIpcClientType 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); - } - } -} diff --git a/src/lib/ipc/IpcServer.h b/src/lib/ipc/IpcServer.h deleted file mode 100644 index b1548776..00000000 --- a/src/lib/ipc/IpcServer.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include "ipc/Ipc.h" -#include "net/TCPListenSocket.h" -#include "net/NetworkAddress.h" -#include "arch/Arch.h" -#include "base/EventTypes.h" - -#include - -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); - virtual ~IpcServer(); - - //! @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, EIpcClientType filterType); - - //@} - //! @name accessors - //@{ - - //! Returns true when there are clients of the specified type connected. - virtual bool hasClients(EIpcClientType 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: - typedef std::list ClientList; - - 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 -}; diff --git a/src/lib/ipc/IpcServerProxy.cpp b/src/lib/ipc/IpcServerProxy.cpp deleted file mode 100644 index 4b64df55..00000000 --- a/src/lib/ipc/IpcServerProxy.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "ipc/IpcServerProxy.h" - -#include "base/Log.h" -#include "base/TMethodEventJob.h" -#include "core/ProtocolUtil.h" -#include "io/IStream.h" -#include "ipc/Ipc.h" -#include "ipc/IpcMessage.h" - -// -// IpcServerProxy -// - -IpcServerProxy::IpcServerProxy(synergy::IStream& stream, IEventQueue* events) : - m_stream(stream), - m_events(events) -{ - m_events->adoptHandler(m_events->forIStream().inputReady(), - stream.getEventTarget(), - new TMethodEventJob( - this, &IpcServerProxy::handleData)); -} - -IpcServerProxy::~IpcServerProxy() -{ - m_events->removeHandler(m_events->forIStream().inputReady(), - m_stream.getEventTarget()); -} - -void -IpcServerProxy::handleData(const Event& /*unused*/, void* /*unused*/) -{ - LOG((CLOG_DEBUG "start ipc handle data")); - - UInt8 code[4]; - UInt32 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, nullptr, 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 kIpcHello: { - const auto& hm = dynamic_cast(message); - ProtocolUtil::writef(&m_stream, kIpcMsgHello, hm.clientType()); - break; - } - - case kIpcCommand: { - const auto& cm = dynamic_cast(message); - const 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() -{ - 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(); -} diff --git a/src/lib/ipc/IpcServerProxy.h b/src/lib/ipc/IpcServerProxy.h deleted file mode 100644 index dc9459a9..00000000 --- a/src/lib/ipc/IpcServerProxy.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include "base/Event.h" -#include "base/EventTypes.h" - -namespace synergy { class IStream; } -class IpcMessage; -class IpcLogLineMessage; -class IEventQueue; - -class IpcServerProxy { - friend class IpcClient; - -public: - IpcServerProxy(synergy::IStream& stream, IEventQueue* events); - virtual ~IpcServerProxy(); - -private: - void send(const IpcMessage& message); - - void handleData(const Event&, void*); - IpcLogLineMessage* parseLogLine(); - void disconnect(); - -private: - synergy::IStream& m_stream; - IEventQueue* m_events; -}; diff --git a/src/lib/platform/CMakeLists.txt b/src/lib/platform/CMakeLists.txt index aee03738..d0fa2bf1 100644 --- a/src/lib/platform/CMakeLists.txt +++ b/src/lib/platform/CMakeLists.txt @@ -40,7 +40,7 @@ add_library(platform STATIC ${sources}) target_link_libraries(platform client ${libs}) if (UNIX) - target_link_libraries(platform io net ipc core client ${libs}) + target_link_libraries(platform io net core client ${libs}) endif() if (APPLE) diff --git a/src/lib/platform/MSWindowsWatchdog.cpp b/src/lib/platform/MSWindowsWatchdog.cpp deleted file mode 100644 index 11d52a4b..00000000 --- a/src/lib/platform/MSWindowsWatchdog.cpp +++ /dev/null @@ -1,588 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2009 Chris Schoeneman - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "platform/MSWindowsWatchdog.h" - -#include "ipc/IpcLogOutputter.h" -#include "ipc/IpcServer.h" -#include "ipc/IpcMessage.h" -#include "ipc/Ipc.h" -#include "core/App.h" -#include "core/ArgsBase.h" -#include "mt/Thread.h" -#include "arch/win32/ArchDaemonWindows.h" -#include "arch/win32/XArchWindows.h" -#include "arch/Arch.h" -#include "base/log_outputters.h" -#include "base/TMethodJob.h" -#include "base/Log.h" -#include "common/Version.h" - -#include -#include -#include - -#define MAXIMUM_WAIT_TIME 3 -enum { - kOutputBufferSize = 4096 -}; - -typedef VOID (WINAPI *SendSas)(BOOL asUser); - -const char g_activeDesktop[] = {"activeDesktop:"}; - -MSWindowsWatchdog::MSWindowsWatchdog( - bool autoDetectCommand, - IpcServer& ipcServer, - IpcLogOutputter& ipcLogOutputter) : - m_thread(NULL), - m_autoDetectCommand(autoDetectCommand), - m_monitoring(true), - m_commandChanged(false), - m_stdOutWrite(NULL), - m_stdOutRead(NULL), - m_ipcServer(ipcServer), - m_ipcLogOutputter(ipcLogOutputter), - m_elevateProcess(false), - m_processFailures(0), - m_processRunning(false), - m_fileLogOutputter(NULL), - m_autoElevated(false), - m_ready(false) -{ - m_mutex = ARCH->newMutex(); - m_condVar = ARCH->newCondVar(); -} - -MSWindowsWatchdog::~MSWindowsWatchdog() -{ - if (m_condVar != NULL) { - ARCH->closeCondVar(m_condVar); - } - - if (m_mutex != NULL) { - ARCH->closeMutex(m_mutex); - } -} - -void -MSWindowsWatchdog::startAsync() -{ - m_thread = new Thread(new TMethodJob( - this, &MSWindowsWatchdog::mainLoop, nullptr)); - - m_outputThread = new Thread(new TMethodJob( - this, &MSWindowsWatchdog::outputLoop, nullptr)); -} - -void -MSWindowsWatchdog::stop() -{ - m_monitoring = false; - - m_thread->wait(5); - delete m_thread; - - m_outputThread->wait(5); - delete m_outputThread; -} - -HANDLE -MSWindowsWatchdog::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security) -{ - HANDLE sourceToken; - - BOOL tokenRet = OpenProcessToken( - process, - TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, - &sourceToken); - - if (!tokenRet) { - LOG((CLOG_ERR "could not open token, process handle: %d", process)); - throw XArch(new XArchEvalWindows()); - } - - LOG((CLOG_DEBUG "got token %i, duplicating", sourceToken)); - - HANDLE newToken; - BOOL duplicateRet = DuplicateTokenEx( - sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security, - SecurityImpersonation, TokenPrimary, &newToken); - - if (!duplicateRet) { - LOG((CLOG_ERR "could not duplicate token %i", sourceToken)); - throw XArch(new XArchEvalWindows()); - } - - LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); - return newToken; -} - -HANDLE -MSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security) -{ - // always elevate if we are at the vista/7 login screen. we could also - // elevate for the uac dialog (consent.exe) but this would be pointless, - // since synergy would re-launch as non-elevated after the desk switch, - // and so would be unusable with the new elevated process taking focus. - if (m_elevateProcess - || m_autoElevated - || m_session.isProcessInSession("logonui.exe", NULL)) { - - LOG((CLOG_DEBUG "getting elevated token, %s", - (m_elevateProcess ? "elevation required" : "at login screen"))); - - HANDLE process; - if (!m_session.isProcessInSession("winlogon.exe", &process)) { - throw XMSWindowsWatchdogError("cannot get user token without winlogon.exe"); - } - - return duplicateProcessToken(process, security); - } - else { - LOG((CLOG_DEBUG "getting non-elevated token")); - return m_session.getUserToken(security); - } -} - -void -MSWindowsWatchdog::mainLoop(void*) -{ - shutdownExistingProcesses(); - - SendSas sendSasFunc = NULL; - HINSTANCE sasLib = LoadLibrary("sas.dll"); - if (sasLib) { - LOG((CLOG_DEBUG "found sas.dll")); - sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS"); - } - - SECURITY_ATTRIBUTES saAttr; - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - saAttr.lpSecurityDescriptor = NULL; - - if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) { - throw XArch(new XArchEvalWindows()); - } - - ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); - - while (m_monitoring) { - try { - - if (m_processRunning && getCommand().empty()) { - LOG((CLOG_INFO "process started but command is empty, shutting down")); - shutdownExistingProcesses(); - m_processRunning = false; - continue; - } - - if (m_processFailures != 0) { - // increasing backoff period, maximum of 10 seconds. - int timeout = (m_processFailures * 2) < 10 ? (m_processFailures * 2) : 10; - LOG((CLOG_INFO "backing off, wait=%ds, failures=%d", timeout, m_processFailures)); - ARCH->sleep(timeout); - } - - if (!getCommand().empty() && ((m_processFailures != 0) || m_session.hasChanged() || m_commandChanged)) { - startProcess(); - } - - if (m_processRunning && !isProcessActive()) { - - m_processFailures++; - m_processRunning = false; - - LOG((CLOG_WARN "detected application not running, pid=%d", - m_processInfo.dwProcessId)); - } - - if (sendSasFunc != NULL) { - - HANDLE sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS"); - if (sendSasEvent != NULL) { - - // use SendSAS event to wait for next session (timeout 1 second). - if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0) { - LOG((CLOG_DEBUG "calling SendSAS")); - sendSasFunc(FALSE); - } - - CloseHandle(sendSasEvent); - continue; - } - } - - // if the sas event failed, wait by sleeping. - ARCH->sleep(1); - - } - catch (std::exception& e) { - LOG((CLOG_ERR "failed to launch, error: %s", e.what())); - m_processFailures++; - m_processRunning = false; - continue; - } - catch (...) { - LOG((CLOG_ERR "failed to launch, unknown error.")); - m_processFailures++; - m_processRunning = false; - continue; - } - } - - if (m_processRunning) { - LOG((CLOG_DEBUG "terminated running process on exit")); - shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20); - } - - LOG((CLOG_DEBUG "watchdog main thread finished")); -} - -bool -MSWindowsWatchdog::isProcessActive() -{ - DWORD exitCode; - GetExitCodeProcess(m_processInfo.hProcess, &exitCode); - return exitCode == STILL_ACTIVE; -} - -void -MSWindowsWatchdog::setFileLogOutputter(FileLogOutputter* outputter) -{ - m_fileLogOutputter = outputter; -} - -void -MSWindowsWatchdog::startProcess() -{ - if (m_command.empty()) { - throw XMSWindowsWatchdogError("cannot start process, command is empty"); - } - - m_commandChanged = false; - - if (m_processRunning) { - LOG((CLOG_DEBUG "closing existing process to make way for new one")); - shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20); - m_processRunning = false; - } - - m_session.updateActiveSession(); - - SECURITY_ATTRIBUTES sa; - ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); - - getActiveDesktop(&sa); - - ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); - HANDLE userToken = getUserToken(&sa); - m_elevateProcess = m_autoElevated ? m_autoElevated : m_elevateProcess; - m_autoElevated = false; - - // patch by Jack Zhou and Henry Tung - // set UIAccess to fix Windows 8 GUI interaction - // http://symless.com/spit/issues/details/3338/#c70 - DWORD uiAccess = 1; - SetTokenInformation(userToken, TokenUIAccess, &uiAccess, sizeof(DWORD)); - - BOOL createRet = doStartProcess(m_command, userToken, &sa); - - if (!createRet) { - LOG((CLOG_ERR "could not launch")); - DWORD exitCode = 0; - GetExitCodeProcess(m_processInfo.hProcess, &exitCode); - LOG((CLOG_ERR "exit code: %d", exitCode)); - throw XArch(new XArchEvalWindows); - } - else { - // wait for program to fail. - ARCH->sleep(1); - if (!isProcessActive()) { - throw XMSWindowsWatchdogError("process immediately stopped"); - } - - m_processRunning = true; - m_processFailures = 0; - - LOG((CLOG_DEBUG "started process, session=%i, elevated: %s, command=%s", - m_session.getActiveSessionId(), - m_elevateProcess ? "yes" : "no", - m_command.c_str())); - } -} - -BOOL -MSWindowsWatchdog::doStartProcess(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa) -{ - // clear, as we're reusing process info struct - ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); - - STARTUPINFO si; - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - si.lpDesktop = "winsta0\\Default"; // TODO: maybe this should be \winlogon if we have logonui.exe? - si.hStdError = m_stdOutWrite; - si.hStdOutput = m_stdOutWrite; - si.dwFlags |= STARTF_USESTDHANDLES; - - LPVOID environment; - BOOL blockRet = CreateEnvironmentBlock(&environment, userToken, FALSE); - if (!blockRet) { - LOG((CLOG_ERR "could not create environment block")); - throw XArch(new XArchEvalWindows); - } - - DWORD creationFlags = - NORMAL_PRIORITY_CLASS | - CREATE_NO_WINDOW | - CREATE_UNICODE_ENVIRONMENT; - - // re-launch in current active user session - LOG((CLOG_INFO "starting new process")); - BOOL createRet = CreateProcessAsUser( - userToken, NULL, LPSTR(command.c_str()), - sa, NULL, TRUE, creationFlags, - environment, NULL, &si, &m_processInfo); - - DestroyEnvironmentBlock(environment); - CloseHandle(userToken); - - return createRet; -} - -void -MSWindowsWatchdog::setCommand(const std::string& command, bool elevate) -{ - LOG((CLOG_INFO "service command updated")); - m_command = command; - m_elevateProcess = elevate; - m_commandChanged = true; - m_processFailures = 0; -} - -std::string -MSWindowsWatchdog::getCommand() const -{ - if (!m_autoDetectCommand) { - return m_command; - } - - // seems like a fairly convoluted way to get the process name - const char* launchName = App::instance().argsBase().m_pname; - std::string args = ARCH->commandLine(); - - // build up a full command line - std::stringstream cmdTemp; - cmdTemp << launchName << args; - - std::string cmd = cmdTemp.str(); - - size_t i; - std::string find = "--relaunch"; - while ((i = cmd.find(find)) != std::string::npos) { - cmd.replace(i, find.length(), ""); - } - - return cmd; -} - -void -MSWindowsWatchdog::outputLoop(void*) -{ - // +1 char for \0 - CHAR buffer[kOutputBufferSize + 1]; - - while (m_monitoring) { - - DWORD bytesRead; - BOOL success = ReadFile(m_stdOutRead, buffer, kOutputBufferSize, &bytesRead, NULL); - - // assume the process has gone away? slow down - // the reads until another one turns up. - if (!success || bytesRead == 0) { - ARCH->sleep(1); - } - else { - buffer[bytesRead] = '\0'; - - testOutput(buffer); - - m_ipcLogOutputter.write(kINFO, buffer); - - if (m_fileLogOutputter != NULL) { - m_fileLogOutputter->write(kINFO, buffer); - } - } - } -} - -void -MSWindowsWatchdog::shutdownProcess(HANDLE handle, DWORD pid, int timeout) -{ - DWORD exitCode; - GetExitCodeProcess(handle, &exitCode); - if (exitCode != STILL_ACTIVE) { - return; - } - - IpcShutdownMessage shutdown; - m_ipcServer.send(shutdown, kIpcClientNode); - - // wait for process to exit gracefully. - double start = ARCH->time(); - while (true) { - - GetExitCodeProcess(handle, &exitCode); - if (exitCode != STILL_ACTIVE) { - // yay, we got a graceful shutdown. there should be no hook in use errors! - LOG((CLOG_INFO "process %d was shutdown gracefully", pid)); - break; - } - else { - - double elapsed = (ARCH->time() - start); - if (elapsed > timeout) { - // if timeout reached, kill forcefully. - // calling TerminateProcess on synergy is very bad! - // it causes the hook DLL to stay loaded in some apps, - // making it impossible to start synergy again. - LOG((CLOG_WARN "shutdown timed out after %d secs, forcefully terminating", (int)elapsed)); - TerminateProcess(handle, kExitSuccess); - break; - } - - ARCH->sleep(1); - } - } -} - -void -MSWindowsWatchdog::shutdownExistingProcesses() -{ - // first we need to take a snapshot of the running processes - HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); - if (snapshot == INVALID_HANDLE_VALUE) { - LOG((CLOG_ERR "could not get process snapshot")); - throw XArch(new XArchEvalWindows); - } - - PROCESSENTRY32 entry; - entry.dwSize = sizeof(PROCESSENTRY32); - - // get the first process, and if we can't do that then it's - // unlikely we can go any further - BOOL gotEntry = Process32First(snapshot, &entry); - if (!gotEntry) { - LOG((CLOG_ERR "could not get first process entry")); - throw XArch(new XArchEvalWindows); - } - - // now just iterate until we can find winlogon.exe pid - DWORD pid = 0; - while (gotEntry) { - - // make sure we're not checking the system process - if (entry.th32ProcessID != 0) { - - if (_stricmp(entry.szExeFile, "synergyc.exe") == 0 || - _stricmp(entry.szExeFile, "synergys.exe") == 0) { - - HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID); - shutdownProcess(handle, entry.th32ProcessID, 10); - } - } - - // now move on to the next entry (if we're not at the end) - gotEntry = Process32Next(snapshot, &entry); - if (!gotEntry) { - - DWORD err = GetLastError(); - if (err != ERROR_NO_MORE_FILES) { - - // only worry about error if it's not the end of the snapshot - LOG((CLOG_ERR "could not get subsiquent process entry")); - throw XArch(new XArchEvalWindows); - } - } - } - - CloseHandle(snapshot); - m_processRunning = false; -} - -void -MSWindowsWatchdog::getActiveDesktop(LPSECURITY_ATTRIBUTES security) -{ - String installedDir = ARCH->getInstalledDirectory(); - if (!installedDir.empty()) { - String syntoolCommand; - syntoolCommand.append("\"").append(installedDir).append("\\").append("syntool").append("\""); - syntoolCommand.append(" --get-active-desktop"); - - m_session.updateActiveSession(); - bool elevateProcess = m_elevateProcess; - m_elevateProcess = true; - HANDLE userToken = getUserToken(security); - m_elevateProcess = elevateProcess; - - BOOL createRet = doStartProcess(syntoolCommand, userToken, security); - - if (!createRet) { - DWORD rc = GetLastError(); - RevertToSelf(); - } - else { - LOG((CLOG_DEBUG "launched syntool to check active desktop")); - } - - ARCH->lockMutex(m_mutex); - int waitTime = 0; - while (!m_ready) { - if (waitTime >= MAXIMUM_WAIT_TIME) { - break; - } - - ARCH->waitCondVar(m_condVar, m_mutex, 1.0); - waitTime++; - } - m_ready = false; - ARCH->unlockMutex(m_mutex); - } -} - -void -MSWindowsWatchdog::testOutput(String buffer) -{ - // HACK: check standard output seems hacky. - size_t i = buffer.find(g_activeDesktop); - if (i != String::npos) { - size_t s = sizeof(g_activeDesktop); - String defaultDesktop("Default"); - String sub = buffer.substr(i + s - 1, defaultDesktop.size()); - if (sub != defaultDesktop) { - m_autoElevated = true; - } - - ARCH->lockMutex(m_mutex); - m_ready = true; - ARCH->broadcastCondVar(m_condVar); - ARCH->unlockMutex(m_mutex); - } -} diff --git a/src/lib/platform/MSWindowsWatchdog.h b/src/lib/platform/MSWindowsWatchdog.h deleted file mode 100644 index 18145e2c..00000000 --- a/src/lib/platform/MSWindowsWatchdog.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2009 Chris Schoeneman - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include "platform/MSWindowsSession.h" -#include "core/XSynergy.h" -#include "arch/IArchMultithread.h" - -#define WIN32_LEAN_AND_MEAN -#include -#include -#include - -class Thread; -class IpcLogOutputter; -class IpcServer; -class FileLogOutputter; - -class MSWindowsWatchdog { -public: - MSWindowsWatchdog( - bool autoDetectCommand, - IpcServer& ipcServer, - IpcLogOutputter& ipcLogOutputter); - virtual ~MSWindowsWatchdog(); - - void startAsync(); - std::string getCommand() const; - void setCommand(const std::string& command, bool elevate); - void stop(); - bool isProcessActive(); - void setFileLogOutputter(FileLogOutputter* outputter); - -private: - void mainLoop(void*); - void outputLoop(void*); - void shutdownProcess(HANDLE handle, DWORD pid, int timeout); - void shutdownExistingProcesses(); - HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security); - HANDLE getUserToken(LPSECURITY_ATTRIBUTES security); - void startProcess(); - BOOL doStartProcess(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa); - void sendSas(); - void getActiveDesktop(LPSECURITY_ATTRIBUTES security); - void testOutput(String buffer); - -private: - Thread* m_thread; - bool m_autoDetectCommand; - std::string m_command; - bool m_monitoring; - bool m_commandChanged; - HANDLE m_stdOutWrite; - HANDLE m_stdOutRead; - Thread* m_outputThread; - IpcServer& m_ipcServer; - IpcLogOutputter& m_ipcLogOutputter; - bool m_elevateProcess; - MSWindowsSession m_session; - PROCESS_INFORMATION m_processInfo; - int m_processFailures; - bool m_processRunning; - FileLogOutputter* m_fileLogOutputter; - bool m_autoElevated; - ArchMutex m_mutex; - ArchCond m_condVar; - bool m_ready; -}; - -//! Relauncher error -/*! -An error occured in the process watchdog. -*/ -class XMSWindowsWatchdogError : public XSynergy { -public: - XMSWindowsWatchdogError(const String& msg) : XSynergy(msg) { } - - // XBase overrides - virtual String getWhat() const throw() { return what(); } -}; diff --git a/src/test/integtests/CMakeLists.txt b/src/test/integtests/CMakeLists.txt index 87bb17ea..9a5afa64 100644 --- a/src/test/integtests/CMakeLists.txt +++ b/src/test/integtests/CMakeLists.txt @@ -68,4 +68,4 @@ endif() add_executable(integtests ${sources}) target_link_libraries(integtests - arch base client common io ipc mt net platform server core gtest gmock ${libs}) + arch base client common io mt net platform server core gtest gmock ${libs}) diff --git a/src/test/integtests/ipc/IpcTests.cpp b/src/test/integtests/ipc/IpcTests.cpp deleted file mode 100644 index 127e481c..00000000 --- a/src/test/integtests/ipc/IpcTests.cpp +++ /dev/null @@ -1,205 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012-2016 Symless Ltd. - * Copyright (C) 2012 Nick Bolton - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -// TODO(andrew): fix, tests failing intermittently on mac. -#ifndef WINAPI_CARBON - -#define TEST_ENV - -#include "test/global/TestEventQueue.h" -#include "arch/Arch.h" -#include "base/EventQueue.h" -#include "base/Log.h" -#include "base/String.h" -#include "base/TMethodEventJob.h" -#include "base/TMethodJob.h" -#include "ipc/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/global/gtest.h" - -#define TEST_IPC_PORT 24802 - -class IpcTests : public ::testing::Test -{ -public: - IpcTests(); - ~IpcTests() override; - - void connectToServer_handleMessageReceived(const Event& /*e*/, void* /*unused*/); - void sendMessageToServer_serverHandleMessageReceived(const Event& /*e*/, void* /*unused*/); - void sendMessageToClient_serverHandleClientConnected(const Event& /*e*/, void* /*unused*/); - void sendMessageToClient_clientHandleMessageReceived(const Event& /*e*/, void* /*unused*/); - -public: - SocketMultiplexer m_multiplexer; - bool m_connectToServer_helloMessageReceived{false}; - bool m_connectToServer_hasClientNode{false}; - IpcServer* m_connectToServer_server{nullptr}; - String m_sendMessageToServer_receivedString; - String m_sendMessageToClient_receivedString; - IpcClient* m_sendMessageToServer_client{nullptr}; - IpcServer* m_sendMessageToClient_server{nullptr}; - TestEventQueue m_events; - -}; - -TEST_F(IpcTests, connectToServer) -{ - SocketMultiplexer socketMultiplexer; - IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); - server.listen(); - m_connectToServer_server = &server; - - m_events.adoptHandler( - m_events.forIpcServer().messageReceived(), &server, - new TMethodEventJob( - this, &IpcTests::connectToServer_handleMessageReceived)); - - IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); - 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, TEST_IPC_PORT); - server.listen(); - - // event handler sends "test" command to server. - m_events.adoptHandler( - m_events.forIpcServer().messageReceived(), &server, - new TMethodEventJob( - this, &IpcTests::sendMessageToServer_serverHandleMessageReceived)); - - IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); - 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, TEST_IPC_PORT); - server.listen(); - m_sendMessageToClient_server = &server; - - // event handler sends "test" log line to client. - m_events.adoptHandler( - m_events.forIpcServer().messageReceived(), &server, - new TMethodEventJob( - this, &IpcTests::sendMessageToClient_serverHandleClientConnected)); - - IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); - client.connect(); - - m_events.adoptHandler( - m_events.forIpcClient().messageReceived(), &client, - new TMethodEventJob( - 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() -{ -} - -IpcTests::~IpcTests() -= default; - -void -IpcTests::connectToServer_handleMessageReceived(const Event& e, void* /*unused*/) -{ - auto* m = dynamic_cast(e.getDataObject()); - if (m->type() == kIpcHello) { - m_connectToServer_hasClientNode = - m_connectToServer_server->hasClients(kIpcClientNode); - m_connectToServer_helloMessageReceived = true; - m_events.raiseQuitEvent(); - } -} - -void -IpcTests::sendMessageToServer_serverHandleMessageReceived(const Event& e, void* /*unused*/) -{ - auto* m = dynamic_cast(e.getDataObject()); - if (m->type() == kIpcHello) { - LOG((CLOG_DEBUG "client said hello, sending test to server")); - IpcCommandMessage m("test", true); - m_sendMessageToServer_client->send(m); - } - else if (m->type() == kIpcCommand) { - auto* cm = dynamic_cast(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* /*unused*/) -{ - auto* m = dynamic_cast(e.getDataObject()); - if (m->type() == kIpcHello) { - LOG((CLOG_DEBUG "client said hello, sending test to client")); - IpcLogLineMessage m("test"); - m_sendMessageToClient_server->send(m, kIpcClientNode); - } -} - -void -IpcTests::sendMessageToClient_clientHandleMessageReceived(const Event& e, void* /*unused*/) -{ - auto* m = dynamic_cast(e.getDataObject()); - if (m->type() == kIpcLogLine) { - auto* llm = dynamic_cast(m); - LOG((CLOG_DEBUG "got ipc log message, %d", llm->logLine().c_str())); - m_sendMessageToClient_receivedString = llm->logLine(); - m_events.raiseQuitEvent(); - } -} - -#endif // WINAPI_CARBON diff --git a/src/test/mock/ipc/MockIpcServer.h b/src/test/mock/ipc/MockIpcServer.h deleted file mode 100644 index 1ea4d33b..00000000 --- a/src/test/mock/ipc/MockIpcServer.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2015-2016 Symless Ltd. - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#pragma once - -#include "ipc/IpcServer.h" -#include "ipc/IpcMessage.h" -#include "arch/Arch.h" - -#include "test/global/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_METHOD0(listen, void()); - MOCK_METHOD2(send, void(const IpcMessage&, EIpcClientType)); - MOCK_CONST_METHOD1(hasClients, bool(EIpcClientType)); - - 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&, EIpcClientType) { - ArchMutexLock lock(m_sendMutex); - ARCH->broadcastCondVar(m_sendCond); - } - - ArchCond m_sendCond; - ArchMutex m_sendMutex; -}; diff --git a/src/test/mock/synergy/MockEventQueue.h b/src/test/mock/synergy/MockEventQueue.h index dbfbe3bb..6dcadd39 100644 --- a/src/test/mock/synergy/MockEventQueue.h +++ b/src/test/mock/synergy/MockEventQueue.h @@ -45,10 +45,6 @@ public: MOCK_METHOD0(getSystemTarget, void*()); MOCK_METHOD0(forClient, ClientEvents&()); MOCK_METHOD0(forIStream, IStreamEvents&()); - MOCK_METHOD0(forIpcClient, IpcClientEvents&()); - MOCK_METHOD0(forIpcClientProxy, IpcClientProxyEvents&()); - MOCK_METHOD0(forIpcServer, IpcServerEvents&()); - MOCK_METHOD0(forIpcServerProxy, IpcServerProxyEvents&()); MOCK_METHOD0(forIDataSocket, IDataSocketEvents&()); MOCK_METHOD0(forIListenSocket, IListenSocketEvents&()); MOCK_METHOD0(forISocket, ISocketEvents&()); diff --git a/src/test/unittests/CMakeLists.txt b/src/test/unittests/CMakeLists.txt index 75d57813..788e1e50 100644 --- a/src/test/unittests/CMakeLists.txt +++ b/src/test/unittests/CMakeLists.txt @@ -68,4 +68,4 @@ endif() add_executable(unittests ${sources}) target_link_libraries(unittests - arch base client server common io net platform server core mt ipc gtest gmock shared ${libs}) + arch base client server common io net platform server core mt gtest gmock shared ${libs}) diff --git a/src/test/unittests/ipc/IpcLogOutputterTests.cpp b/src/test/unittests/ipc/IpcLogOutputterTests.cpp deleted file mode 100644 index 142e54fc..00000000 --- a/src/test/unittests/ipc/IpcLogOutputterTests.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2015-2016 Symless Ltd. - * - * This package is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * found in the file LICENSE that should have accompanied this file. - * - * This package is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#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 "test/global/gmock.h" -#include "test/global/gtest.h" - -// HACK: ipc logging only used on windows anyway -#if WINAPI_MSWINDOWS - -using ::testing::_; -using ::testing::Return; -using ::testing::Matcher; -using ::testing::MatcherCast; -using ::testing::Property; -using ::testing::StrEq; -using ::testing::AtLeast; - -using namespace synergy; - -inline const Matcher IpcLogLineMessageEq(const String& s) { - const Matcher m( - Property(&IpcLogLineMessage::logLine, StrEq(s))); - return MatcherCast(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, kIpcClientUnknown, 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, kIpcClientUnknown, 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, kIpcClientUnknown, 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, kIpcClientUnknown, 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 diff --git a/src/test/unittests/synergy/GenericArgsParsingTests.cpp b/src/test/unittests/synergy/GenericArgsParsingTests.cpp index 066c3acb..cf6d8ff2 100644 --- a/src/test/unittests/synergy/GenericArgsParsingTests.cpp +++ b/src/test/unittests/synergy/GenericArgsParsingTests.cpp @@ -260,22 +260,6 @@ TEST(GenericArgsParsingTests, parseGenericArgs_noTrayCmd_disableTrayTrue) EXPECT_EQ(1, i); } -TEST(GenericArgsParsingTests, parseGenericArgs_ipcCmd_enableIpcTrue) -{ - int i = 1; - const int argc = 2; - const char* kIpcCmd[argc] = { "stub", "--ipc" }; - - ArgParser argParser(nullptr); - ArgsBase argsBase; - argParser.setArgsBase(argsBase); - - argParser.parseGenericArgs(argc, kIpcCmd, i); - - EXPECT_EQ(true, argsBase.m_enableIpc); - EXPECT_EQ(1, i); -} - #ifndef WINAPI_XWINDOWS TEST(GenericArgsParsingTests, parseGenericArgs_dragDropCmdOnNonLinux_enableDragDropTrue) {