summaryrefslogtreecommitdiffstats
path: root/src/lib/ipc/IpcServer.cpp
diff options
context:
space:
mode:
authorLibravatarUnit 193 <unit193@ubuntu.com>2018-04-25 18:07:30 -0400
committerLibravatarUnit 193 <unit193@ubuntu.com>2018-04-25 18:07:30 -0400
commit9b1b081cfdb1c0fb6457278775e0823f8bc10f62 (patch)
treece8840148d8445055ba9e4f12263b2208f234c16 /src/lib/ipc/IpcServer.cpp
Import Upstream version 2.0.0+dfsgupstream/2.0.0+dfsg
Diffstat (limited to 'src/lib/ipc/IpcServer.cpp')
-rw-r--r--src/lib/ipc/IpcServer.cpp187
1 files changed, 187 insertions, 0 deletions
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);
+ }
+ }
+}