fully replaced gui/daemon named pipes ipc with tcp ipc.
This commit is contained in:
parent
79d73bd163
commit
7d5fbde71d
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ private:
|
|||
|
||||
public:
|
||||
IStream& m_stream;
|
||||
bool m_enableLog;
|
||||
|
||||
private:
|
||||
static CEvent::Type s_messageReceivedEvent;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue