fully replaced gui/daemon named pipes ipc with tcp ipc.

This commit is contained in:
Nick Bolton 2012-07-03 14:15:05 +00:00
parent 79d73bd163
commit 7d5fbde71d
25 changed files with 315 additions and 399 deletions

View File

@ -22,6 +22,7 @@ set(inc
../../lib/base
../../lib/common
../../lib/io
../../lib/ipc
../../lib/mt
../../lib/net
../../lib/platform
@ -47,7 +48,7 @@ if (VNC_SUPPORT)
endif()
target_link_libraries(synergyd
arch base common io mt net platform synergy ${libs})
arch base common io ipc mt net platform synergy ${libs})
if (CONF_CPACK)
install(TARGETS

View File

@ -36,7 +36,8 @@ SOURCES += src/main.cpp \
src/QSynergyApplication.cpp \
src/VersionChecker.cpp \
src/SetupWizard.cpp \
src/IpcLogReader.cpp
src/IpcLogReader.cpp \
src/IpcClient.cpp
HEADERS += src/MainWindow.h \
src/AboutDialog.h \
src/ServerConfig.h \
@ -59,7 +60,8 @@ HEADERS += src/MainWindow.h \
src/QSynergyApplication.h \
src/VersionChecker.h \
src/SetupWizard.h \
src/IpcLogReader.h
src/IpcLogReader.h \
src/IpcClient.h
RESOURCES += res/Synergy.qrc
RC_FILE = res/win/Synergy.rc
TRANSLATIONS = res/lang/nl_NL.ts

83
src/gui/src/IpcClient.cpp Normal file
View File

@ -0,0 +1,83 @@
/*
* synergy -- mouse and keyboard sharing utility
* 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 COPYING 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 <http://www.gnu.org/licenses/>.
*/
#include "IpcClient.h"
#include <QTcpSocket>
#include <QHostAddress>
IpcClient::IpcClient()
{
m_Socket = new QTcpSocket(this);
connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read()));
connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError)));
}
IpcClient::~IpcClient()
{
}
void IpcClient::connectToHost()
{
m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT);
}
void IpcClient::read()
{
QDataStream stream(m_Socket);
char codeBuf[1];
stream.readRawData(codeBuf, 1);
switch (codeBuf[0]) {
case kIpcLogLine: {
char lenBuf[1];
stream.readRawData(lenBuf, 1);
char* data = new char[lenBuf[0] + 1];
stream.readRawData(data, lenBuf[0]);
data[(int)lenBuf[0]] = 0;
QString s(data);
readLogLine(s);
}
break;
}
}
void IpcClient::error(QAbstractSocket::SocketError error)
{
errorMessage("ERROR: Could not connect to background service.");
}
void IpcClient::write(unsigned char code, unsigned char length, const char* data)
{
QDataStream stream(m_Socket);
char codeBuf[1];
codeBuf[0] = code;
stream.writeRawData(codeBuf, 1);
switch (code) {
case kIpcCommand: {
char lenBuf[1];
lenBuf[0] = length;
stream.writeRawData(lenBuf, 1);
stream.writeRawData(data, length);
}
break;
}
}

View File

@ -17,32 +17,37 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <QObject>
#include <QAbstractSocket>
#include "IArchLog.h"
#include <windows.h>
#define IPC_PORT 24801
#define ARCH_IPC_LOG CArchIpcLogWindows
class QTcpSocket;
class CThread;
class IpcClient : public QObject
{
Q_OBJECT
//! Win32 implementation of IArchLog (IPC version)
class CArchIpcLogWindows : public IArchLog {
public:
CArchIpcLogWindows();
virtual ~CArchIpcLogWindows();
IpcClient();
virtual ~IpcClient();
// IArchLog overrides
virtual void openLog(const char* name);
virtual void closeLog();
virtual void showLog(bool showIfEmpty);
virtual void writeLog(ELevel, const char*);
void connectToHost();
void write(unsigned char code, unsigned char length, const char* data);
private slots:
void read();
void error(QAbstractSocket::SocketError error);
signals:
void readLogLine(const QString& text);
void errorMessage(const QString& text);
private:
void connectThread(void*);
private:
HANDLE m_pipe;
CThread* m_listenThread;
bool m_connected;
QTcpSocket* m_Socket;
};
enum EIpcMessage {
kIpcLogLine,
kIpcCommand
};

View File

@ -17,6 +17,8 @@
#define WEBSITE_ADDRESS "synergy-foss.org"
#include <iostream>
#include "MainWindow.h"
#include "AboutDialog.h"
#include "ServerConfigDialog.h"
@ -88,8 +90,10 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) :
if (appConfig.processMode() == Service)
{
connect(&m_IpcLogReader, SIGNAL(receivedLine(const QString&)), this, SLOT(appendLog(const QString&)));
m_IpcLogReader.start();
connect(&m_IpcClient, SIGNAL(readLogLine(const QString&)), this, SLOT(appendLog(const QString&)));
connect(&m_IpcClient, SIGNAL(errorMessage(const QString&)), this, SLOT(appendLog(const QString&)));
m_IpcClient.connectToHost();
appendLog("INFO: Connecting to background service...");
}
}
@ -665,55 +669,9 @@ void MainWindow::on_m_pButtonConfigureServer_clicked()
void MainWindow::sendDaemonCommand(const QString& command, bool showErrors)
{
sendIpcMessage(Command, command.toStdString().c_str(), showErrors);
}
// TODO: put this in an IPC client class.
void MainWindow::sendIpcMessage(qIpcMessage type, const char* data, bool showErrors)
{
#if defined(Q_OS_WIN)
const WCHAR* name = L"\\\\.\\pipe\\Synergy";
char message[1024];
message[0] = type;
char* messagePtr = message;
messagePtr++;
strcpy(messagePtr, data);
HANDLE pipe = CreateFile(
name, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (showErrors && pipe == INVALID_HANDLE_VALUE)
{
appendLog(QString("ERROR: could not connect to service, error: ") +
QString::number(GetLastError()));
return;
}
DWORD dwMode = PIPE_READMODE_MESSAGE;
BOOL stateSuccess = SetNamedPipeHandleState(pipe, &dwMode, NULL, NULL);
if (showErrors && !stateSuccess)
{
appendLog(QString("ERROR: could not set service pipe state, error: ") +
QString::number(GetLastError()));
return;
}
DWORD written;
BOOL writeSuccess = WriteFile(
pipe, message, strlen(message), &written, NULL);
if (showErrors && !writeSuccess)
{
appendLog(QString("ERROR: could not write to service pipe, error: ") +
QString::number(GetLastError()));
return;
}
CloseHandle(pipe);
#endif
std::string s = command.toStdString();
const char* data = s.c_str();
m_IpcClient.write(Command, strlen(data), data);
}
void MainWindow::on_m_pActionWizard_triggered()

View File

@ -30,7 +30,7 @@
#include "ServerConfig.h"
#include "AppConfig.h"
#include "VersionChecker.h"
#include "IpcLogReader.h"
#include "IpcClient.h"
class QAction;
class QMenu;
@ -142,7 +142,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
bool m_alreadyHidden;
VersionChecker m_versionChecker;
SetupWizard* m_SetupWizard;
IpcLogReader m_IpcLogReader;
IpcClient m_IpcClient;
};
#endif

View File

@ -42,7 +42,6 @@
# include "CArchDaemonWindows.h"
# include "CArchFileWindows.h"
# include "CArchLogWindows.h"
# include "CArchIpcLogWindows.h"
# include "CArchMiscWindows.h"
# include "CArchMultithreadWindows.h"
# include "CArchNetworkWinsock.h"
@ -57,7 +56,6 @@
# include "CArchDaemonUnix.h"
# include "CArchFileUnix.h"
# include "CArchLogUnix.h"
# include "CArchIpcLogUnix.h"
# if HAVE_PTHREAD
# include "CArchMultithreadPosix.h"
# endif
@ -111,7 +109,6 @@ public:
*/
static CArch* getInstance();
ARCH_IPC_LOG& ipcLog() const { return (ARCH_IPC_LOG&)m_ipcLog; }
ARCH_PLUGIN& plugin() const { return (ARCH_PLUGIN&)m_plugin; }
private:
@ -120,7 +117,6 @@ private:
private:
static CArch* s_instance;
ARCH_IPC_LOG m_ipcLog;
ARCH_PLUGIN m_plugin;
};

View File

@ -1,111 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman, Nick Bolton, Sorin Sbarnea
*
* 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 COPYING 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 <http://www.gnu.org/licenses/>.
*/
#include "CArchIpcLogWindows.h"
#include "CArchMiscWindows.h"
#include "XArch.h"
#include "CThread.h"
#include "TMethodJob.h"
#include "CArch.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
//
// CArchIpcLogWindows
//
CArchIpcLogWindows::CArchIpcLogWindows() :
m_pipe(NULL),
m_listenThread(NULL),
m_connected(false)
{
}
CArchIpcLogWindows::~CArchIpcLogWindows()
{
if (m_listenThread != NULL)
delete m_listenThread;
}
void
CArchIpcLogWindows::openLog(const char* name)
{
// grant access to everyone.
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, static_cast<PACL>(0), FALSE);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
HANDLE pipe = CreateNamedPipe(
TEXT("\\\\.\\pipe\\SynergyLog"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
1024, 1024, 0, &sa);
if (pipe == INVALID_HANDLE_VALUE)
XArch("could not create named pipe.");
m_pipe = pipe;
m_listenThread = new CThread(new TMethodJob<CArchIpcLogWindows>(
this, &CArchIpcLogWindows::connectThread, nullptr));
}
void
CArchIpcLogWindows::connectThread(void*)
{
// HACK: this seems like a hacky pile of bollocks. it will continuously call
// ConnectNamedPipe every second. if there is no client, it will block,
// but if there is a client it will return FALSE and GetLastError() will
// be ERROR_PIPE_CONNECTED. in any other case, the client has gone away
// and ConnectNamedPipe will go back to blocking (waiting for the client
// to reconnect).
while (true) {
BOOL result = ConnectNamedPipe(m_pipe, NULL);
if ((result == TRUE) || (GetLastError() == ERROR_PIPE_CONNECTED)) {
m_connected = true;
ARCH->sleep(1);
} else {
DisconnectNamedPipe(m_pipe);
}
}
}
void
CArchIpcLogWindows::closeLog()
{
}
void
CArchIpcLogWindows::showLog(bool)
{
}
void
CArchIpcLogWindows::writeLog(ELevel level, const char* data)
{
if (!m_connected)
return;
DWORD bytesWritten;
WriteFile(m_pipe, data, (DWORD)strlen(data), &bytesWritten, NULL);
}

View File

@ -27,7 +27,6 @@ if (WIN32)
CArchDaemonWindows.h
CArchFileWindows.h
CArchLogWindows.h
CArchIpcLogWindows.h
CArchMiscWindows.h
CArchMultithreadWindows.h
CArchNetworkWinsock.h
@ -51,7 +50,6 @@ if (WIN32)
CArchDaemonWindows.cpp
CArchFileWindows.cpp
CArchLogWindows.cpp
CArchIpcLogWindows.cpp
CArchMiscWindows.cpp
CArchMultithreadWindows.cpp
CArchNetworkWinsock.cpp
@ -71,7 +69,6 @@ elseif (UNIX)
CArchDaemonUnix.cpp
CArchFileUnix.cpp
CArchLogUnix.cpp
CArchIpcLogUnix.cpp
CArchMultithreadPosix.cpp
CArchNetworkBSD.cpp
CArchSleepUnix.cpp

View File

@ -262,41 +262,3 @@ CFileLogOutputter::close() {}
void
CFileLogOutputter::show(bool showIfEmpty) {}
//
// CConsoleLogOutputter
//
CIpcLogOutputter::CIpcLogOutputter()
{
}
CIpcLogOutputter::~CIpcLogOutputter()
{
}
void
CIpcLogOutputter::open(const char* title)
{
ARCH->ipcLog().openLog(title);
}
void
CIpcLogOutputter::close()
{
ARCH->ipcLog().closeLog();
}
void
CIpcLogOutputter::show(bool showIfEmpty)
{
ARCH->ipcLog().showLog(showIfEmpty);
}
bool
CIpcLogOutputter::write(ELevel level, const char* msg)
{
ARCH->ipcLog().writeLog(level, msg);
return true;
}

View File

@ -99,22 +99,6 @@ public:
virtual bool write(ELevel level, const char* message);
};
//! Write log to GUI over IPC
/*!
This outputter writes output to the GUI via IPC.
*/
class CIpcLogOutputter : public ILogOutputter {
public:
CIpcLogOutputter();
virtual ~CIpcLogOutputter();
// ILogOutputter overrides
virtual void open(const char* title);
virtual void close();
virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char* message);
};
//! Write log to system log only
/*!
Creating an object of this type inserts a CStopLogOutputter followed

View File

@ -25,7 +25,8 @@
CEvent::Type CIpcClientProxy::s_messageReceivedEvent = CEvent::kUnknown;
CIpcClientProxy::CIpcClientProxy(IStream& stream) :
m_stream(stream)
m_stream(stream),
m_enableLog(false)
{
EVENTQUEUE->adoptHandler(m_stream.getInputReadyEvent(),
stream.getEventTarget(),
@ -45,12 +46,16 @@ CIpcClientProxy::handleData(const CEvent&, void*)
UInt8 code[1];
UInt32 n = m_stream.read(code, 1);
while (n != 0) {
UInt8 type = code[0];
CIpcMessage* m = new CIpcMessage();
m->m_type = code[1];
m->m_type = type;
LOG((CLOG_DEBUG "ipc client proxy read: %d", code[0]));
switch (code[0]) {
if (m_enableLog) {
LOG((CLOG_DEBUG "ipc client proxy read: %d", code[0]));
}
switch (type) {
case kIpcCommand:
m->m_data = parseCommand();
break;
@ -71,7 +76,9 @@ CIpcClientProxy::handleData(const CEvent&, void*)
void
CIpcClientProxy::send(const CIpcMessage& message)
{
LOG((CLOG_DEBUG "ipc client proxy write: %d", message.m_type));
if (m_enableLog) {
LOG((CLOG_DEBUG "ipc client proxy write: %d", message.m_type));
}
UInt8 code[1];
code[0] = message.m_type;
@ -80,17 +87,21 @@ CIpcClientProxy::send(const CIpcMessage& message)
switch (message.m_type) {
case kIpcLogLine: {
CString* s = (CString*)message.m_data;
const char* data = s->c_str();
int len = strlen(data);
UInt8 len[1];
len[0] = s->size();
m_stream.write(len, 1);
UInt8 lenBuf[1];
lenBuf[0] = len;
m_stream.write(lenBuf, 1);
m_stream.write(s->c_str(), s->size());
m_stream.write(data, len);
}
break;
default:
LOG((CLOG_ERR "message not supported: %d", message.m_type));
if (m_enableLog) {
LOG((CLOG_ERR "message not supported: %d", message.m_type));
}
break;
}
}
@ -110,7 +121,9 @@ CIpcClientProxy::parseCommand()
void
CIpcClientProxy::disconnect()
{
LOG((CLOG_NOTE "disconnect, closing stream"));
if (m_enableLog) {
LOG((CLOG_NOTE "disconnect, closing stream"));
}
m_stream.close();
}

View File

@ -40,6 +40,7 @@ private:
public:
IStream& m_stream;
bool m_enableLog;
private:
static CEvent::Type s_messageReceivedEvent;

View File

@ -15,32 +15,41 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CArchIpcLogUnix.h"
#include "CIpcLogOutputter.h"
#include "CIpcServer.h"
#include "CIpcMessage.h"
#include "Ipc.h"
CArchIpcLogUnix::CArchIpcLogUnix()
CIpcLogOutputter::CIpcLogOutputter(CIpcServer& ipcServer) :
m_ipcServer(ipcServer)
{
}
CArchIpcLogUnix::~CArchIpcLogUnix()
CIpcLogOutputter::~CIpcLogOutputter()
{
}
void
CArchIpcLogUnix::openLog(const char* name)
CIpcLogOutputter::open(const char* title)
{
}
void
CArchIpcLogUnix::closeLog()
CIpcLogOutputter::close()
{
}
void
CArchIpcLogUnix::showLog(bool showIfEmpty)
CIpcLogOutputter::show(bool showIfEmpty)
{
}
void
CArchIpcLogUnix::writeLog(ELevel, const char*)
bool
CIpcLogOutputter::write(ELevel level, const char* msg)
{
CIpcMessage message;
message.m_type = kIpcLogLine;
message.m_data = new CString(msg);
m_ipcServer.send(message);
return true;
}

View File

@ -17,18 +17,25 @@
#pragma once
#include "IArchLog.h"
#include "ILogOutputter.h"
#define ARCH_IPC_LOG CArchIpcLogUnix
class CIpcServer;
class CArchIpcLogUnix : public IArchLog {
//! Write log to GUI over IPC
/*!
This outputter writes output to the GUI via IPC.
*/
class CIpcLogOutputter : public ILogOutputter {
public:
CArchIpcLogUnix();
virtual ~CArchIpcLogUnix();
CIpcLogOutputter(CIpcServer& ipcServer);
virtual ~CIpcLogOutputter();
// IArchLog overrides
virtual void openLog(const char* name);
virtual void closeLog();
virtual void showLog(bool showIfEmpty);
virtual void writeLog(ELevel, const char*);
// ILogOutputter overrides
virtual void open(const char* title);
virtual void close();
virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char* message);
private:
CIpcServer& m_ipcServer;
};

View File

@ -17,11 +17,15 @@
#include "CIpcMessage.h"
CIpcMessage::CIpcMessage()
CIpcMessage::CIpcMessage() :
m_type(0),
m_data(nullptr)
{
}
CIpcMessage::~CIpcMessage()
{
delete m_data;
if (m_data != nullptr) {
delete m_data;
}
}

View File

@ -57,13 +57,15 @@ CIpcServer::handleClientConnecting(const CEvent&, void*)
if (stream == NULL) {
return;
}
// when there is already a client connected, this causes stack overflow,
//
LOG((CLOG_NOTE "accepted ipc client connection"));
// TODO: delete on disconnect
CIpcClientProxy* proxy = new CIpcClientProxy(*stream);
m_clients.insert(proxy);
EVENTQUEUE->addEvent(CEvent(getClientConnectedEvent(), this, proxy));
EVENTQUEUE->addEvent(CEvent(getClientConnectedEvent(), this, proxy, CEvent::kDontFreeData));
}
CEvent::Type

View File

@ -20,6 +20,7 @@ set(inc
CIpcServerProxy.h
CIpcClientProxy.h
CIpcMessage.h
CIpcLogOutputter.h
)
set(src
@ -28,6 +29,7 @@ set(src
CIpcServerProxy.cpp
CIpcClientProxy.cpp
CIpcMessage.cpp
CIpcLogOutputter.cpp
)
if (WIN32)

View File

@ -25,6 +25,7 @@
#include "XArchWindows.h"
#include "CApp.h"
#include "CArgsBase.h"
#include "CIpcLogOutputter.h"
#include <Tlhelp32.h>
#include <UserEnv.h>
@ -42,7 +43,8 @@ CMSWindowsRelauncher::CMSWindowsRelauncher(bool autoDetectCommand) :
m_running(true),
m_commandChanged(false),
m_stdOutWrite(NULL),
m_stdOutRead(NULL)
m_stdOutRead(NULL),
m_ipcLogOutputter(nullptr)
{
}
@ -403,7 +405,7 @@ CMSWindowsRelauncher::outputLoop(void*)
else {
// send process output over IPC to GUI.
buffer[bytesRead] = '\0';
ARCH->ipcLog().writeLog(kINFO, buffer);
m_ipcLogOutputter->write(kINFO, buffer);
}
}

View File

@ -23,6 +23,7 @@
#include <list>
class CThread;
class CIpcLogOutputter;
class CMSWindowsRelauncher {
public:
@ -42,6 +43,9 @@ private:
void sendIpcMessage(int type, const char* data);
void shutdownProcess(const PROCESS_INFORMATION& pi, int timeout);
public:
CIpcLogOutputter* m_ipcLogOutputter;
private:
CThread* m_thread;
bool m_autoDetectCommand;

View File

@ -137,6 +137,7 @@ set(inc
../common
../mt
../synergy
../ipc
)
if (UNIX)
@ -191,5 +192,5 @@ if (WIN32)
endif()
if (UNIX)
target_link_libraries(platform synergy ${libs})
target_link_libraries(platform ipc synergy ${libs})
endif()

View File

@ -38,6 +38,11 @@
#include "CMSWindowsRelauncher.h"
#include "CMSWindowsDebugOutputter.h"
#include "TMethodJob.h"
#include "TMethodEventJob.h"
#include "CIpcClientProxy.h"
#include "CIpcMessage.h"
#include "CSocketMultiplexer.h"
#include "CIpcLogOutputter.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
@ -69,9 +74,11 @@ winMainLoopStatic(int, const char**)
}
#endif
CDaemonApp::CDaemonApp()
CDaemonApp::CDaemonApp() :
m_ipcServer(nullptr),
m_ipcLogOutputter(nullptr)
#if SYSAPI_WIN32
: m_relauncher(false)
,m_relauncher(false)
#endif
{
s_instance = this;
@ -91,15 +98,9 @@ CDaemonApp::run(int argc, char** argv)
CArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL));
#endif
// send logging to gui via ipc
CLOG->insert(new CIpcLogOutputter());
#if SYSAPI_WIN32
// sends debug messages to visual studio console window.
CLOG->insert(new CMSWindowsDebugOutputter());
CThread pipeThread(new TMethodJob<CDaemonApp>(
this, &CDaemonApp::pipeThread, nullptr));
#endif
// default log level to system setting.
@ -174,6 +175,23 @@ CDaemonApp::mainLoop(bool logToFile)
CEventQueue eventQueue;
// create socket multiplexer. this must happen after daemonization
// on unix because threads evaporate across a fork().
CSocketMultiplexer multiplexer;
// uses event queue, must be created here.
m_ipcServer = new CIpcServer();
eventQueue.adoptHandler(
CIpcServer::getClientConnectedEvent(), m_ipcServer,
new TMethodEventJob<CDaemonApp>(this, &CDaemonApp::handleIpcConnected));
m_ipcServer->listen();
// send logging to gui via ipc, log system adopts outputter.
m_ipcLogOutputter = new CIpcLogOutputter(*m_ipcServer);
CLOG->insert(m_ipcLogOutputter);
#if SYSAPI_WIN32
// HACK: create a dummy screen, which can handle system events
// (such as a stop request from the service controller).
@ -181,6 +199,8 @@ CDaemonApp::mainLoop(bool logToFile)
CGameDeviceInfo gameDevice;
CScreen dummyScreen(new CMSWindowsScreen(false, true, gameDevice));
m_relauncher.m_ipcLogOutputter = m_ipcLogOutputter;
string command = ARCH->setting("Command");
if (command != "") {
LOG((CLOG_INFO "using last known command: %s", command.c_str()));
@ -190,22 +210,27 @@ CDaemonApp::mainLoop(bool logToFile)
m_relauncher.startAsync();
#endif
EVENTQUEUE->loop();
eventQueue.loop();
#if SYSAPI_WIN32
m_relauncher.stop();
#endif
eventQueue.removeHandler(
CIpcServer::getClientConnectedEvent(), m_ipcServer);
delete m_ipcServer;
DAEMON_RUNNING(false);
}
catch (XArch& e) {
LOG((CLOG_ERR, e.what().c_str()));
LOG((CLOG_ERR "xarch exception: %s", e.what().c_str()));
}
catch (std::exception& e) {
LOG((CLOG_ERR, e.what()));
LOG((CLOG_ERR "std exception: %s", e.what()));
}
catch (...) {
LOG((CLOG_ERR, "Unrecognized error."));
LOG((CLOG_ERR "unrecognized error."));
}
}
@ -237,71 +262,35 @@ CDaemonApp::logPath()
#endif
}
#ifdef SYSAPI_WIN32
void
CDaemonApp::pipeThread(void*)
CDaemonApp::handleIpcConnected(const CEvent& e, void*)
{
// TODO: move this to an IPC server class.
while (true) {
// grant access to everyone.
SECURITY_DESCRIPTOR sd;
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&sd, TRUE, static_cast<PACL>(0), FALSE);
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
HANDLE pipe = CreateNamedPipe(
_T("\\\\.\\pipe\\Synergy"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES,
1024, 1024, 0, &sa);
if (pipe == INVALID_HANDLE_VALUE)
XArch("could not create named pipe.");
LOG((CLOG_DEBUG "opened daemon pipe: %d", pipe));
BOOL connectResult = ConnectNamedPipe(pipe, NULL);
char buffer[1024];
DWORD bytesRead;
while (true) {
if (!ReadFile(pipe, buffer, sizeof(buffer), &bytesRead, NULL)) {
break;
}
buffer[bytesRead] = '\0';
LOG((CLOG_DEBUG "ipc daemon server read: %s", buffer));
try {
handlePipeMessage(buffer);
}
catch (XArch& ex) {
LOG((CLOG_ERR "handle message failed: %s", ex.what().c_str()));
}
}
DisconnectNamedPipe(pipe);
CloseHandle(pipe);
}
LOG((CLOG_INFO "ipc client connected"));
EVENTQUEUE->adoptHandler(
CIpcClientProxy::getMessageReceivedEvent(), e.getData(),
new TMethodEventJob<CDaemonApp>(
this, &CDaemonApp::handleIpcMessage));
}
void
CDaemonApp::handlePipeMessage(char* buffer)
CDaemonApp::handleIpcMessage(const CEvent& e, void*)
{
switch (buffer[0]) {
case kIpcCommand:
{
string command(++buffer);
CIpcMessage& m = *reinterpret_cast<CIpcMessage*>(e.getData());
// store command in system settings. this is used when the daemon
// next starts.
ARCH->setting("Command", command);
LOG((CLOG_DEBUG "ipc message: %d", m.m_type));
switch (m.m_type) {
case kIpcCommand: {
CString& command = *reinterpret_cast<CString*>(m.m_data);
try {
// store command in system settings. this is used when the daemon
// next starts.
ARCH->setting("Command", command);
}
catch (XArch& e) {
//LOG((CLOG_ERR "failed to save setting: %s", e.what().c_str()));
}
// tell the relauncher about the new command. this causes the
// relauncher to stop the existing command and start the new
@ -310,11 +299,8 @@ CDaemonApp::handlePipeMessage(char* buffer)
}
break;
default:
LOG((CLOG_WARN "unrecognized ipc message: %d", buffer[0]));
break;
default:
LOG((CLOG_ERR "ipc message not supported: %d", m.m_type));
break;
}
}
#endif

View File

@ -18,6 +18,7 @@
#pragma once
#include "CArch.h"
#include "CIpcServer.h"
#if SYSAPI_WIN32
#include "CMSWindowsRelauncher.h"
@ -25,6 +26,9 @@
#include <string>
class CEvent;
class CIpcLogOutputter;
class CDaemonApp {
public:
@ -37,16 +41,19 @@ private:
void daemonize();
void foregroundError(const char* message);
std::string logPath();
#if SYSAPI_WIN32
void pipeThread(void*);
void handlePipeMessage(char* buffer);
#endif
void handleIpcConnected(const CEvent&, void*);
void handleIpcMessage(const CEvent&, void*);
public:
static CDaemonApp* s_instance;
#if SYSAPI_WIN32
CMSWindowsRelauncher m_relauncher;
#endif
private:
CIpcServer* m_ipcServer;
CIpcLogOutputter* m_ipcLogOutputter;
};
#define LOG_FILENAME "synergyd.log"

View File

@ -102,6 +102,7 @@ set(inc
../client
../common
../io
../ipc
../mt
../net
../platform
@ -125,5 +126,5 @@ include_directories(${inc})
add_library(synergy STATIC ${src})
if (UNIX)
target_link_libraries(synergy arch client net base platform mt server)
target_link_libraries(synergy arch client ipc net base platform mt server)
endif()

View File

@ -180,7 +180,7 @@ CIpcTests::sendMessageToClient_handleConnected(const CEvent& e, void*)
void
CIpcTests::sendMessageToClient_handleMessageReceived(const CEvent& e, void*)
{
CIpcMessage* m = (CIpcMessage*)e.getData();
CIpcMessage* m = reinterpret_cast<CIpcMessage*>(e.getData());
m_sendMessageToClient_receivedString = *((CString*)m->m_data);
raiseQuitEvent();
}