aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/ipc')
-rw-r--r--src/lib/ipc/CMakeLists.txt28
-rw-r--r--src/lib/ipc/Ipc.cpp24
-rw-r--r--src/lib/ipc/Ipc.h52
-rw-r--r--src/lib/ipc/IpcClient.cpp108
-rw-r--r--src/lib/ipc/IpcClient.h64
-rw-r--r--src/lib/ipc/IpcClientProxy.cpp194
-rw-r--r--src/lib/ipc/IpcClientProxy.h55
-rw-r--r--src/lib/ipc/IpcLogOutputter.cpp228
-rw-r--r--src/lib/ipc/IpcLogOutputter.h119
-rw-r--r--src/lib/ipc/IpcMessage.cpp69
-rw-r--r--src/lib/ipc/IpcMessage.h85
-rw-r--r--src/lib/ipc/IpcServer.cpp187
-rw-r--r--src/lib/ipc/IpcServer.h92
-rw-r--r--src/lib/ipc/IpcServerProxy.cpp123
-rw-r--r--src/lib/ipc/IpcServerProxy.h46
15 files changed, 1474 insertions, 0 deletions
diff --git a/src/lib/ipc/CMakeLists.txt b/src/lib/ipc/CMakeLists.txt
new file mode 100644
index 0000000..3c7302a
--- /dev/null
+++ b/src/lib/ipc/CMakeLists.txt
@@ -0,0 +1,28 @@
+# barrier -- 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 <http://www.gnu.org/licenses/>.
+
+file(GLOB headers "*.h")
+file(GLOB sources "*.cpp")
+
+if (BARRIER_ADD_HEADERS)
+ list(APPEND sources ${headers})
+endif()
+
+add_library(ipc STATIC ${sources})
+
+if (UNIX)
+ target_link_libraries(ipc arch base common mt io net synlib)
+endif()
diff --git a/src/lib/ipc/Ipc.cpp b/src/lib/ipc/Ipc.cpp
new file mode 100644
index 0000000..78b8407
--- /dev/null
+++ b/src/lib/ipc/Ipc.cpp
@@ -0,0 +1,24 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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
new file mode 100644
index 0000000..bc69c08
--- /dev/null
+++ b/src/lib/ipc/Ipc.h
@@ -0,0 +1,52 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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 (barrierc/s).
+extern const char* kIpcMsgHello;
+
+// log line: daemon -> gui
+// $1 = aggregate log lines collected from barriers/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 barriers/c. $2 = true when process must be elevated on ms windows.
+extern const char* kIpcMsgCommand;
+
+// shutdown: daemon -> node
+// the daemon tells barriers/c to shut down gracefully.
+extern const char* kIpcMsgShutdown;
diff --git a/src/lib/ipc/IpcClient.cpp b/src/lib/ipc/IpcClient.cpp
new file mode 100644
index 0000000..4eeae5b
--- /dev/null
+++ b/src/lib/ipc/IpcClient.cpp
@@ -0,0 +1,108 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "ipc/IpcClient.h"
+#include "ipc/Ipc.h"
+#include "ipc/IpcServerProxy.h"
+#include "ipc/IpcMessage.h"
+#include "base/TMethodEventJob.h"
+
+//
+// IpcClient
+//
+
+IpcClient::IpcClient(IEventQueue* events, SocketMultiplexer* socketMultiplexer) :
+ m_serverAddress(NetworkAddress(IPC_HOST, IPC_PORT)),
+ m_socket(events, socketMultiplexer, IArchNetwork::kINET),
+ 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, IArchNetwork::kINET),
+ m_server(nullptr),
+ m_events(events)
+{
+ init();
+}
+
+void
+IpcClient::init()
+{
+ m_serverAddress.resolve();
+}
+
+IpcClient::~IpcClient()
+{
+}
+
+void
+IpcClient::connect()
+{
+ m_events->adoptHandler(
+ m_events->forIDataSocket().connected(), m_socket.getEventTarget(),
+ new TMethodEventJob<IpcClient>(
+ 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<IpcClient>(
+ 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&, void*)
+{
+ 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*)
+{
+ 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
new file mode 100644
index 0000000..1e9bca6
--- /dev/null
+++ b/src/lib/ipc/IpcClient.h
@@ -0,0 +1,64 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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
new file mode 100644
index 0000000..af85eca
--- /dev/null
+++ b/src/lib/ipc/IpcClientProxy.cpp
@@ -0,0 +1,194 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "ipc/IpcClientProxy.h"
+
+#include "ipc/Ipc.h"
+#include "ipc/IpcMessage.h"
+#include "barrier/ProtocolUtil.h"
+#include "io/IStream.h"
+#include "arch/Arch.h"
+#include "base/TMethodEventJob.h"
+#include "base/Log.h"
+
+//
+// IpcClientProxy
+//
+
+IpcClientProxy::IpcClientProxy(barrier::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<IpcClientProxy>(
+ this, &IpcClientProxy::handleData));
+
+ m_events->adoptHandler(
+ m_events->forIStream().outputError(), stream.getEventTarget(),
+ new TMethodEventJob<IpcClientProxy>(
+ this, &IpcClientProxy::handleWriteError));
+
+ m_events->adoptHandler(
+ m_events->forIStream().inputShutdown(), stream.getEventTarget(),
+ new TMethodEventJob<IpcClientProxy>(
+ this, &IpcClientProxy::handleDisconnect));
+
+ m_events->adoptHandler(
+ m_events->forIStream().outputShutdown(), stream.getEventTarget(),
+ new TMethodEventJob<IpcClientProxy>(
+ 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&, void*)
+{
+ disconnect();
+ LOG((CLOG_DEBUG "ipc client disconnected"));
+}
+
+void
+IpcClientProxy::handleWriteError(const Event&, void*)
+{
+ disconnect();
+ LOG((CLOG_DEBUG "ipc client write error"));
+}
+
+void
+IpcClientProxy::handleData(const Event&, void*)
+{
+ // 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, NULL, 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 IpcLogLineMessage& llm = static_cast<const IpcLogLineMessage&>(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<EIpcClientType>(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
new file mode 100644
index 0000000..eaa12c7
--- /dev/null
+++ b/src/lib/ipc/IpcClientProxy.h
@@ -0,0 +1,55 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "ipc/Ipc.h"
+#include "arch/IArchMultithread.h"
+#include "base/EventTypes.h"
+#include "base/Event.h"
+
+namespace barrier { class IStream; }
+class IpcMessage;
+class IpcCommandMessage;
+class IpcHelloMessage;
+class IEventQueue;
+
+class IpcClientProxy {
+ friend class IpcServer;
+
+public:
+ IpcClientProxy(barrier::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:
+ barrier::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
new file mode 100644
index 0000000..984793e
--- /dev/null
+++ b/src/lib/ipc/IpcLogOutputter.cpp
@@ -0,0 +1,228 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "ipc/IpcLogOutputter.h"
+
+#include "ipc/IpcServer.h"
+#include "ipc/IpcMessage.h"
+#include "ipc/Ipc.h"
+#include "ipc/IpcClientProxy.h"
+#include "mt/Thread.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"
+
+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<IpcLogOutputter>(
+ 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, 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*)
+{
+ 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
new file mode 100644
index 0000000..461f022
--- /dev/null
+++ b/src/lib/ipc/IpcLogOutputter.h
@@ -0,0 +1,119 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "arch/Arch.h"
+#include "arch/IArchMultithread.h"
+#include "base/ILogOutputter.h"
+#include "ipc/Ipc.h"
+
+#include <deque>
+
+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* message);
+
+ //! @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<String> 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
new file mode 100644
index 0000000..deef22d
--- /dev/null
+++ b/src/lib/ipc/IpcMessage.cpp
@@ -0,0 +1,69 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "ipc/IpcMessage.h"
+#include "ipc/Ipc.h"
+
+IpcMessage::IpcMessage(UInt8 type) :
+ m_type(type)
+{
+}
+
+IpcMessage::~IpcMessage()
+{
+}
+
+IpcHelloMessage::IpcHelloMessage(EIpcClientType clientType) :
+ IpcMessage(kIpcHello),
+ m_clientType(clientType)
+{
+}
+
+IpcHelloMessage::~IpcHelloMessage()
+{
+}
+
+IpcShutdownMessage::IpcShutdownMessage() :
+IpcMessage(kIpcShutdown)
+{
+}
+
+IpcShutdownMessage::~IpcShutdownMessage()
+{
+}
+
+IpcLogLineMessage::IpcLogLineMessage(const String& logLine) :
+IpcMessage(kIpcLogLine),
+m_logLine(logLine)
+{
+}
+
+IpcLogLineMessage::~IpcLogLineMessage()
+{
+}
+
+IpcCommandMessage::IpcCommandMessage(const String& command, bool elevate) :
+IpcMessage(kIpcCommand),
+m_command(command),
+m_elevate(elevate)
+{
+}
+
+IpcCommandMessage::~IpcCommandMessage()
+{
+}
diff --git a/src/lib/ipc/IpcMessage.h b/src/lib/ipc/IpcMessage.h
new file mode 100644
index 0000000..5cc3d79
--- /dev/null
+++ b/src/lib/ipc/IpcMessage.h
@@ -0,0 +1,85 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#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(const String& logLine);
+ virtual ~IpcLogLineMessage();
+
+ //! Gets the log line.
+ String logLine() const { return m_logLine; }
+
+private:
+ String m_logLine;
+};
+
+class IpcCommandMessage : public IpcMessage {
+public:
+ IpcCommandMessage(const 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
new file mode 100644
index 0000000..e05a913
--- /dev/null
+++ b/src/lib/ipc/IpcServer.cpp
@@ -0,0 +1,187 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "ipc/IpcServer.h"
+
+#include "ipc/Ipc.h"
+#include "ipc/IpcClientProxy.h"
+#include "ipc/IpcMessage.h"
+#include "net/IDataSocket.h"
+#include "io/IStream.h"
+#include "base/IEventQueue.h"
+#include "base/TMethodEventJob.h"
+#include "base/Event.h"
+#include "base/Log.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, IArchNetwork::kINET);
+
+ m_clientsMutex = ARCH->newMutex();
+ m_address.resolve();
+
+ m_events->adoptHandler(
+ m_events->forIListenSocket().connecting(), m_socket,
+ new TMethodEventJob<IpcServer>(
+ this, &IpcServer::handleClientConnecting));
+}
+
+IpcServer::~IpcServer()
+{
+ if (m_mock) {
+ return;
+ }
+
+ if (m_socket != nullptr) {
+ 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&, void*)
+{
+ barrier::IStream* stream = m_socket->accept();
+ if (stream == NULL) {
+ return;
+ }
+
+ LOG((CLOG_DEBUG "accepted ipc client connection"));
+
+ ARCH->lockMutex(m_clientsMutex);
+ IpcClientProxy* 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<IpcServer>(
+ this, &IpcServer::handleClientDisconnected));
+
+ m_events->adoptHandler(
+ m_events->forIpcClientProxy().messageReceived(), proxy,
+ new TMethodEventJob<IpcServer>(
+ this, &IpcServer::handleMessageReceived));
+
+ m_events->addEvent(Event(
+ m_events->forIpcServer().clientConnected(), this, proxy, Event::kDontFreeData));
+}
+
+void
+IpcServer::handleClientDisconnected(const Event& e, void*)
+{
+ IpcClientProxy* proxy = static_cast<IpcClientProxy*>(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*)
+{
+ 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
new file mode 100644
index 0000000..d9bbe3e
--- /dev/null
+++ b/src/lib/ipc/IpcServer.h
@@ -0,0 +1,92 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "ipc/Ipc.h"
+#include "net/TCPListenSocket.h"
+#include "net/NetworkAddress.h"
+#include "arch/Arch.h"
+#include "base/EventTypes.h"
+
+#include <list>
+
+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<IpcClientProxy*> 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
new file mode 100644
index 0000000..820e1ab
--- /dev/null
+++ b/src/lib/ipc/IpcServerProxy.cpp
@@ -0,0 +1,123 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "ipc/IpcServerProxy.h"
+
+#include "ipc/IpcMessage.h"
+#include "ipc/Ipc.h"
+#include "barrier/ProtocolUtil.h"
+#include "io/IStream.h"
+#include "base/TMethodEventJob.h"
+#include "base/Log.h"
+
+//
+// IpcServerProxy
+//
+
+IpcServerProxy::IpcServerProxy(barrier::IStream& stream, IEventQueue* events) :
+ m_stream(stream),
+ m_events(events)
+{
+ m_events->adoptHandler(m_events->forIStream().inputReady(),
+ stream.getEventTarget(),
+ new TMethodEventJob<IpcServerProxy>(
+ this, &IpcServerProxy::handleData));
+}
+
+IpcServerProxy::~IpcServerProxy()
+{
+ m_events->removeHandler(m_events->forIStream().inputReady(),
+ m_stream.getEventTarget());
+}
+
+void
+IpcServerProxy::handleData(const Event&, void*)
+{
+ 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, NULL, 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 IpcHelloMessage& hm = static_cast<const IpcHelloMessage&>(message);
+ ProtocolUtil::writef(&m_stream, kIpcMsgHello, hm.clientType());
+ break;
+ }
+
+ case kIpcCommand: {
+ const IpcCommandMessage& cm = static_cast<const IpcCommandMessage&>(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
new file mode 100644
index 0000000..f2218a4
--- /dev/null
+++ b/src/lib/ipc/IpcServerProxy.h
@@ -0,0 +1,46 @@
+/*
+ * barrier -- 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 <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "base/Event.h"
+#include "base/EventTypes.h"
+
+namespace barrier { class IStream; }
+class IpcMessage;
+class IpcLogLineMessage;
+class IEventQueue;
+
+class IpcServerProxy {
+ friend class IpcClient;
+
+public:
+ IpcServerProxy(barrier::IStream& stream, IEventQueue* events);
+ virtual ~IpcServerProxy();
+
+private:
+ void send(const IpcMessage& message);
+
+ void handleData(const Event&, void*);
+ IpcLogLineMessage* parseLogLine();
+ void disconnect();
+
+private:
+ barrier::IStream& m_stream;
+ IEventQueue* m_events;
+};