1 /*
2  * synergy -- mouse and keyboard sharing utility
3  * Copyright (C) 2012-2016 Symless Ltd.
4  * Copyright (C) 2012 Nick Bolton
5  *
6  * This package is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * found in the file LICENSE that should have accompanied this file.
9  *
10  * This package is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "ipc/IpcServer.h"
20 
21 #include "ipc/Ipc.h"
22 #include "ipc/IpcClientProxy.h"
23 #include "ipc/IpcMessage.h"
24 #include "net/IDataSocket.h"
25 #include "io/IStream.h"
26 #include "base/IEventQueue.h"
27 #include "base/TMethodEventJob.h"
28 #include "base/Event.h"
29 #include "base/Log.h"
30 
31 //
32 // IpcServer
33 //
34 
IpcServer(IEventQueue * events,SocketMultiplexer * socketMultiplexer)35 IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer) :
36     m_mock(false),
37     m_events(events),
38     m_socketMultiplexer(socketMultiplexer),
39     m_socket(nullptr),
40     m_address(NetworkAddress(IPC_HOST, IPC_PORT))
41 {
42     init();
43 }
44 
IpcServer(IEventQueue * events,SocketMultiplexer * socketMultiplexer,int port)45 IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port) :
46     m_mock(false),
47     m_events(events),
48     m_socketMultiplexer(socketMultiplexer),
49     m_address(NetworkAddress(IPC_HOST, port))
50 {
51     init();
52 }
53 
54 void
init()55 IpcServer::init()
56 {
57     m_socket = new TCPListenSocket(m_events, m_socketMultiplexer, IArchNetwork::EAddressFamily::kINET);
58 
59     m_clientsMutex = ARCH->newMutex();
60     m_address.resolve();
61 
62     m_events->adoptHandler(
63         m_events->forIListenSocket().connecting(), m_socket,
64         new TMethodEventJob<IpcServer>(
65         this, &IpcServer::handleClientConnecting));
66 }
67 
~IpcServer()68 IpcServer::~IpcServer()
69 {
70     if (m_mock) {
71         return;
72     }
73 
74     if (m_socket != nullptr) {
75         delete m_socket;
76     }
77 
78     ARCH->lockMutex(m_clientsMutex);
79     ClientList::iterator it;
80     for (it = m_clients.begin(); it != m_clients.end(); it++) {
81         deleteClient(*it);
82     }
83     m_clients.clear();
84     ARCH->unlockMutex(m_clientsMutex);
85     ARCH->closeMutex(m_clientsMutex);
86 
87     m_events->removeHandler(m_events->forIListenSocket().connecting(), m_socket);
88 }
89 
90 void
listen()91 IpcServer::listen()
92 {
93     m_socket->bind(m_address);
94 }
95 
96 void
handleClientConnecting(const Event &,void *)97 IpcServer::handleClientConnecting(const Event&, void*)
98 {
99     synergy::IStream* stream = m_socket->accept();
100     if (stream == NULL) {
101         return;
102     }
103 
104     LOG((CLOG_DEBUG "accepted ipc client connection"));
105 
106     ARCH->lockMutex(m_clientsMutex);
107     IpcClientProxy* proxy = new IpcClientProxy(*stream, m_events);
108     m_clients.push_back(proxy);
109     ARCH->unlockMutex(m_clientsMutex);
110 
111     m_events->adoptHandler(
112         m_events->forIpcClientProxy().disconnected(), proxy,
113         new TMethodEventJob<IpcServer>(
114         this, &IpcServer::handleClientDisconnected));
115 
116     m_events->adoptHandler(
117         m_events->forIpcClientProxy().messageReceived(), proxy,
118         new TMethodEventJob<IpcServer>(
119         this, &IpcServer::handleMessageReceived));
120 
121     m_events->addEvent(Event(
122         m_events->forIpcServer().clientConnected(), this, proxy, Event::kDontFreeData));
123 }
124 
125 void
handleClientDisconnected(const Event & e,void *)126 IpcServer::handleClientDisconnected(const Event& e, void*)
127 {
128     IpcClientProxy* proxy = static_cast<IpcClientProxy*>(e.getTarget());
129 
130     ArchMutexLock lock(m_clientsMutex);
131     m_clients.remove(proxy);
132     deleteClient(proxy);
133 
134     LOG((CLOG_DEBUG "ipc client proxy removed, connected=%d", m_clients.size()));
135 }
136 
137 void
handleMessageReceived(const Event & e,void *)138 IpcServer::handleMessageReceived(const Event& e, void*)
139 {
140     Event event(m_events->forIpcServer().messageReceived(), this);
141     event.setDataObject(e.getDataObject());
142     m_events->addEvent(event);
143 }
144 
145 void
deleteClient(IpcClientProxy * proxy)146 IpcServer::deleteClient(IpcClientProxy* proxy)
147 {
148     m_events->removeHandler(m_events->forIpcClientProxy().messageReceived(), proxy);
149     m_events->removeHandler(m_events->forIpcClientProxy().disconnected(), proxy);
150     delete proxy;
151 }
152 
153 bool
hasClients(EIpcClientType clientType) const154 IpcServer::hasClients(EIpcClientType clientType) const
155 {
156     ArchMutexLock lock(m_clientsMutex);
157 
158     if (m_clients.empty()) {
159         return false;
160     }
161 
162     ClientList::const_iterator it;
163     for (it = m_clients.begin(); it != m_clients.end(); it++) {
164         // at least one client is alive and type matches, there are clients.
165         IpcClientProxy* p = *it;
166         if (!p->m_disconnecting && p->m_clientType == clientType) {
167             return true;
168         }
169     }
170 
171     // all clients must be disconnecting, no active clients.
172     return false;
173 }
174 
175 void
send(const IpcMessage & message,EIpcClientType filterType)176 IpcServer::send(const IpcMessage& message, EIpcClientType filterType)
177 {
178     ArchMutexLock lock(m_clientsMutex);
179 
180     ClientList::iterator it;
181     for (it = m_clients.begin(); it != m_clients.end(); it++) {
182         IpcClientProxy* proxy = *it;
183         if (proxy->m_clientType == filterType) {
184             proxy->send(message);
185         }
186     }
187 }
188