diff --git a/src/cmd/synergyd/CMakeLists.txt b/src/cmd/synergyd/CMakeLists.txt
index dfdb9274..3cb2410b 100644
--- a/src/cmd/synergyd/CMakeLists.txt
+++ b/src/cmd/synergyd/CMakeLists.txt
@@ -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
diff --git a/src/gui/gui.pro b/src/gui/gui.pro
index 13464d4e..e86d1c08 100644
--- a/src/gui/gui.pro
+++ b/src/gui/gui.pro
@@ -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
diff --git a/src/gui/src/IpcClient.cpp b/src/gui/src/IpcClient.cpp
new file mode 100644
index 00000000..ee0f9012
--- /dev/null
+++ b/src/gui/src/IpcClient.cpp
@@ -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 .
+ */
+
+#include "IpcClient.h"
+#include
+#include
+
+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;
+ }
+}
diff --git a/src/lib/arch/CArchIpcLogWindows.h b/src/gui/src/IpcClient.h
similarity index 55%
rename from src/lib/arch/CArchIpcLogWindows.h
rename to src/gui/src/IpcClient.h
index 85158a0e..5786f070 100644
--- a/src/lib/arch/CArchIpcLogWindows.h
+++ b/src/gui/src/IpcClient.h
@@ -1,48 +1,53 @@
-/*
- * 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 .
- */
-
-#pragma once
-
-#define WIN32_LEAN_AND_MEAN
-
-#include "IArchLog.h"
-#include
-
-#define ARCH_IPC_LOG CArchIpcLogWindows
-
-class CThread;
-
-//! Win32 implementation of IArchLog (IPC version)
-class CArchIpcLogWindows : public IArchLog {
-public:
- CArchIpcLogWindows();
- virtual ~CArchIpcLogWindows();
-
- // IArchLog overrides
- virtual void openLog(const char* name);
- virtual void closeLog();
- virtual void showLog(bool showIfEmpty);
- virtual void writeLog(ELevel, const char*);
-
-private:
- void connectThread(void*);
-
-private:
- HANDLE m_pipe;
- CThread* m_listenThread;
- bool m_connected;
-};
+/*
+ * 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 .
+ */
+
+#pragma once
+
+#include
+#include
+
+#define IPC_PORT 24801
+
+class QTcpSocket;
+
+class IpcClient : public QObject
+{
+ Q_OBJECT
+
+public:
+ IpcClient();
+ virtual ~IpcClient();
+
+ 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:
+ QTcpSocket* m_Socket;
+};
+
+enum EIpcMessage {
+ kIpcLogLine,
+ kIpcCommand
+};
diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp
index 3c12a142..8574490d 100644
--- a/src/gui/src/MainWindow.cpp
+++ b/src/gui/src/MainWindow.cpp
@@ -17,6 +17,8 @@
#define WEBSITE_ADDRESS "synergy-foss.org"
+#include
+
#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()
diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h
index d0dfb9b7..6c2bf76a 100644
--- a/src/gui/src/MainWindow.h
+++ b/src/gui/src/MainWindow.h
@@ -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
diff --git a/src/lib/arch/CArch.h b/src/lib/arch/CArch.h
index a6efe54c..c011c95d 100644
--- a/src/lib/arch/CArch.h
+++ b/src/lib/arch/CArch.h
@@ -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;
};
diff --git a/src/lib/arch/CArchIpcLogWindows.cpp b/src/lib/arch/CArchIpcLogWindows.cpp
deleted file mode 100644
index 8cf02104..00000000
--- a/src/lib/arch/CArchIpcLogWindows.cpp
+++ /dev/null
@@ -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 .
- */
-
-#include "CArchIpcLogWindows.h"
-#include "CArchMiscWindows.h"
-#include "XArch.h"
-#include "CThread.h"
-#include "TMethodJob.h"
-#include "CArch.h"
-
-#define WIN32_LEAN_AND_MEAN
-#include
-
-//
-// 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(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(
- 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);
-}
diff --git a/src/lib/arch/CMakeLists.txt b/src/lib/arch/CMakeLists.txt
index 34337ae4..adce4c37 100644
--- a/src/lib/arch/CMakeLists.txt
+++ b/src/lib/arch/CMakeLists.txt
@@ -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
diff --git a/src/lib/base/LogOutputters.cpp b/src/lib/base/LogOutputters.cpp
index aeb5fd63..4d9fb787 100644
--- a/src/lib/base/LogOutputters.cpp
+++ b/src/lib/base/LogOutputters.cpp
@@ -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;
-}
diff --git a/src/lib/base/LogOutputters.h b/src/lib/base/LogOutputters.h
index 8fa26bac..24727be4 100644
--- a/src/lib/base/LogOutputters.h
+++ b/src/lib/base/LogOutputters.h
@@ -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
diff --git a/src/lib/ipc/CIpcClientProxy.cpp b/src/lib/ipc/CIpcClientProxy.cpp
index 440e0b71..ca4967c4 100644
--- a/src/lib/ipc/CIpcClientProxy.cpp
+++ b/src/lib/ipc/CIpcClientProxy.cpp
@@ -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();
}
diff --git a/src/lib/ipc/CIpcClientProxy.h b/src/lib/ipc/CIpcClientProxy.h
index 6797ea68..381c3849 100644
--- a/src/lib/ipc/CIpcClientProxy.h
+++ b/src/lib/ipc/CIpcClientProxy.h
@@ -40,6 +40,7 @@ private:
public:
IStream& m_stream;
+ bool m_enableLog;
private:
static CEvent::Type s_messageReceivedEvent;
diff --git a/src/lib/arch/CArchIpcLogUnix.cpp b/src/lib/ipc/CIpcLogOutputter.cpp
similarity index 57%
rename from src/lib/arch/CArchIpcLogUnix.cpp
rename to src/lib/ipc/CIpcLogOutputter.cpp
index 14a44e0e..0a42af6a 100644
--- a/src/lib/arch/CArchIpcLogUnix.cpp
+++ b/src/lib/ipc/CIpcLogOutputter.cpp
@@ -1,11 +1,11 @@
/*
* 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
@@ -15,32 +15,41 @@
* along with this program. If not, see .
*/
-#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;
}
diff --git a/src/lib/arch/CArchIpcLogUnix.h b/src/lib/ipc/CIpcLogOutputter.h
similarity index 59%
rename from src/lib/arch/CArchIpcLogUnix.h
rename to src/lib/ipc/CIpcLogOutputter.h
index 2f11d02e..34ca561c 100644
--- a/src/lib/arch/CArchIpcLogUnix.h
+++ b/src/lib/ipc/CIpcLogOutputter.h
@@ -1,11 +1,11 @@
/*
* 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
@@ -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;
};
diff --git a/src/lib/ipc/CIpcMessage.cpp b/src/lib/ipc/CIpcMessage.cpp
index 198f0719..2376d90f 100644
--- a/src/lib/ipc/CIpcMessage.cpp
+++ b/src/lib/ipc/CIpcMessage.cpp
@@ -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;
+ }
}
diff --git a/src/lib/ipc/CIpcServer.cpp b/src/lib/ipc/CIpcServer.cpp
index 383479ff..4fc66d22 100644
--- a/src/lib/ipc/CIpcServer.cpp
+++ b/src/lib/ipc/CIpcServer.cpp
@@ -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
diff --git a/src/lib/ipc/CMakeLists.txt b/src/lib/ipc/CMakeLists.txt
index 44a7945d..7a1c4daf 100644
--- a/src/lib/ipc/CMakeLists.txt
+++ b/src/lib/ipc/CMakeLists.txt
@@ -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)
diff --git a/src/lib/platform/CMSWindowsRelauncher.cpp b/src/lib/platform/CMSWindowsRelauncher.cpp
index 9827ec06..17e8a58f 100644
--- a/src/lib/platform/CMSWindowsRelauncher.cpp
+++ b/src/lib/platform/CMSWindowsRelauncher.cpp
@@ -25,6 +25,7 @@
#include "XArchWindows.h"
#include "CApp.h"
#include "CArgsBase.h"
+#include "CIpcLogOutputter.h"
#include
#include
@@ -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);
}
}
diff --git a/src/lib/platform/CMSWindowsRelauncher.h b/src/lib/platform/CMSWindowsRelauncher.h
index 7b05f31a..c8c12a78 100644
--- a/src/lib/platform/CMSWindowsRelauncher.h
+++ b/src/lib/platform/CMSWindowsRelauncher.h
@@ -23,6 +23,7 @@
#include
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;
diff --git a/src/lib/platform/CMakeLists.txt b/src/lib/platform/CMakeLists.txt
index 1fe7e17a..bb2bd414 100644
--- a/src/lib/platform/CMakeLists.txt
+++ b/src/lib/platform/CMakeLists.txt
@@ -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()
diff --git a/src/lib/synergy/CDaemonApp.cpp b/src/lib/synergy/CDaemonApp.cpp
index 23155423..a5f47911 100644
--- a/src/lib/synergy/CDaemonApp.cpp
+++ b/src/lib/synergy/CDaemonApp.cpp
@@ -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
@@ -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(
- 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(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,84 +262,45 @@ 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(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(
+ 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(e.getData());
+
+ LOG((CLOG_DEBUG "ipc message: %d", m.m_type));
+
+ switch (m.m_type) {
+ case kIpcCommand: {
+ CString& command = *reinterpret_cast(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()));
+ }
- // store command in system settings. this is used when the daemon
- // next starts.
- ARCH->setting("Command", command);
-
// tell the relauncher about the new command. this causes the
// relauncher to stop the existing command and start the new
// command.
m_relauncher.command(command);
}
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
diff --git a/src/lib/synergy/CDaemonApp.h b/src/lib/synergy/CDaemonApp.h
index a87d5d2d..2c9ecb8f 100644
--- a/src/lib/synergy/CDaemonApp.h
+++ b/src/lib/synergy/CDaemonApp.h
@@ -18,6 +18,7 @@
#pragma once
#include "CArch.h"
+#include "CIpcServer.h"
#if SYSAPI_WIN32
#include "CMSWindowsRelauncher.h"
@@ -25,6 +26,9 @@
#include
+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"
diff --git a/src/lib/synergy/CMakeLists.txt b/src/lib/synergy/CMakeLists.txt
index 1706c3b4..69b0dae9 100644
--- a/src/lib/synergy/CMakeLists.txt
+++ b/src/lib/synergy/CMakeLists.txt
@@ -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()
diff --git a/src/test/integtests/CIpcTests.cpp b/src/test/integtests/CIpcTests.cpp
index 11c69011..8728a497 100644
--- a/src/test/integtests/CIpcTests.cpp
+++ b/src/test/integtests/CIpcTests.cpp
@@ -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(e.getData());
m_sendMessageToClient_receivedString = *((CString*)m->m_data);
raiseQuitEvent();
}