195 lines
5.5 KiB
C++
195 lines
5.5 KiB
C++
|
/*
|
||
|
* synergy -- mouse and keyboard sharing utility
|
||
|
* Copyright (C) 2004 Chris Schoeneman
|
||
|
*
|
||
|
* 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.
|
||
|
*/
|
||
|
|
||
|
#include "CClientListener.h"
|
||
|
#include "CClientProxy.h"
|
||
|
#include "CClientProxyUnknown.h"
|
||
|
#include "CPacketStreamFilter.h"
|
||
|
#include "IStreamFilterFactory.h"
|
||
|
#include "IDataSocket.h"
|
||
|
#include "IListenSocket.h"
|
||
|
#include "ISocketFactory.h"
|
||
|
#include "XSocket.h"
|
||
|
#include "CLog.h"
|
||
|
#include "IEventQueue.h"
|
||
|
#include "TMethodEventJob.h"
|
||
|
|
||
|
//
|
||
|
// CClientListener
|
||
|
//
|
||
|
|
||
|
CEvent::Type CClientListener::s_connectedEvent = CEvent::kUnknown;
|
||
|
|
||
|
CClientListener::CClientListener(const CNetworkAddress& address,
|
||
|
ISocketFactory* socketFactory,
|
||
|
IStreamFilterFactory* streamFilterFactory) :
|
||
|
m_socketFactory(socketFactory),
|
||
|
m_streamFilterFactory(streamFilterFactory)
|
||
|
{
|
||
|
assert(m_socketFactory != NULL);
|
||
|
|
||
|
try {
|
||
|
// create listen socket
|
||
|
m_listen = m_socketFactory->createListen();
|
||
|
|
||
|
// bind listen address
|
||
|
LOG((CLOG_DEBUG1 "binding listen socket"));
|
||
|
m_listen->bind(address);
|
||
|
}
|
||
|
catch (XSocketAddressInUse&) {
|
||
|
delete m_listen;
|
||
|
delete m_socketFactory;
|
||
|
delete m_streamFilterFactory;
|
||
|
throw;
|
||
|
}
|
||
|
catch (XBase&) {
|
||
|
delete m_listen;
|
||
|
delete m_socketFactory;
|
||
|
delete m_streamFilterFactory;
|
||
|
throw;
|
||
|
}
|
||
|
LOG((CLOG_DEBUG1 "listening for clients"));
|
||
|
|
||
|
// setup event handler
|
||
|
EVENTQUEUE->adoptHandler(IListenSocket::getConnectingEvent(), m_listen,
|
||
|
new TMethodEventJob<CClientListener>(this,
|
||
|
&CClientListener::handleClientConnecting));
|
||
|
}
|
||
|
|
||
|
CClientListener::~CClientListener()
|
||
|
{
|
||
|
LOG((CLOG_DEBUG1 "stop listening for clients"));
|
||
|
|
||
|
// discard already connected clients
|
||
|
for (CNewClients::iterator index = m_newClients.begin();
|
||
|
index != m_newClients.end(); ++index) {
|
||
|
CClientProxyUnknown* client = *index;
|
||
|
EVENTQUEUE->removeHandler(
|
||
|
CClientProxyUnknown::getSuccessEvent(), client);
|
||
|
EVENTQUEUE->removeHandler(
|
||
|
CClientProxyUnknown::getFailureEvent(), client);
|
||
|
EVENTQUEUE->removeHandler(
|
||
|
CClientProxy::getDisconnectedEvent(), client);
|
||
|
delete client;
|
||
|
}
|
||
|
|
||
|
// discard waiting clients
|
||
|
CClientProxy* client = getNextClient();
|
||
|
while (client != NULL) {
|
||
|
delete client;
|
||
|
client = getNextClient();
|
||
|
}
|
||
|
|
||
|
EVENTQUEUE->removeHandler(IListenSocket::getConnectingEvent(), m_listen);
|
||
|
delete m_listen;
|
||
|
delete m_socketFactory;
|
||
|
delete m_streamFilterFactory;
|
||
|
}
|
||
|
|
||
|
CClientProxy*
|
||
|
CClientListener::getNextClient()
|
||
|
{
|
||
|
CClientProxy* client = NULL;
|
||
|
if (!m_waitingClients.empty()) {
|
||
|
client = m_waitingClients.front();
|
||
|
m_waitingClients.pop_front();
|
||
|
EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(), client);
|
||
|
}
|
||
|
return client;
|
||
|
}
|
||
|
|
||
|
CEvent::Type
|
||
|
CClientListener::getConnectedEvent()
|
||
|
{
|
||
|
return CEvent::registerTypeOnce(s_connectedEvent,
|
||
|
"CClientListener::connected");
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CClientListener::handleClientConnecting(const CEvent&, void*)
|
||
|
{
|
||
|
// accept client connection
|
||
|
IStream* stream = m_listen->accept();
|
||
|
if (stream == NULL) {
|
||
|
return;
|
||
|
}
|
||
|
LOG((CLOG_NOTE "accepted client connection"));
|
||
|
|
||
|
// filter socket messages, including a packetizing filter
|
||
|
if (m_streamFilterFactory != NULL) {
|
||
|
stream = m_streamFilterFactory->create(stream, true);
|
||
|
}
|
||
|
stream = new CPacketStreamFilter(stream, true);
|
||
|
|
||
|
// create proxy for unknown client
|
||
|
CClientProxyUnknown* client = new CClientProxyUnknown(stream, 30.0);
|
||
|
m_newClients.insert(client);
|
||
|
|
||
|
// watch for events from unknown client
|
||
|
EVENTQUEUE->adoptHandler(CClientProxyUnknown::getSuccessEvent(), client,
|
||
|
new TMethodEventJob<CClientListener>(this,
|
||
|
&CClientListener::handleUnknownClient, client));
|
||
|
EVENTQUEUE->adoptHandler(CClientProxyUnknown::getFailureEvent(), client,
|
||
|
new TMethodEventJob<CClientListener>(this,
|
||
|
&CClientListener::handleUnknownClient, client));
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CClientListener::handleUnknownClient(const CEvent&, void* vclient)
|
||
|
{
|
||
|
CClientProxyUnknown* unknownClient =
|
||
|
reinterpret_cast<CClientProxyUnknown*>(vclient);
|
||
|
|
||
|
// we should have the client in our new client list
|
||
|
assert(m_newClients.count(unknownClient) == 1);
|
||
|
|
||
|
// get the real client proxy and install it
|
||
|
CClientProxy* client = unknownClient->orphanClientProxy();
|
||
|
if (client != NULL) {
|
||
|
// handshake was successful
|
||
|
m_waitingClients.push_back(client);
|
||
|
EVENTQUEUE->addEvent(CEvent(getConnectedEvent(), this));
|
||
|
|
||
|
// watch for client to disconnect while it's in our queue
|
||
|
EVENTQUEUE->adoptHandler(CClientProxy::getDisconnectedEvent(), client,
|
||
|
new TMethodEventJob<CClientListener>(this,
|
||
|
&CClientListener::handleClientDisconnected,
|
||
|
client));
|
||
|
}
|
||
|
|
||
|
// now finished with unknown client
|
||
|
EVENTQUEUE->removeHandler(CClientProxyUnknown::getSuccessEvent(), client);
|
||
|
EVENTQUEUE->removeHandler(CClientProxyUnknown::getFailureEvent(), client);
|
||
|
m_newClients.erase(unknownClient);
|
||
|
delete unknownClient;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
CClientListener::handleClientDisconnected(const CEvent&, void* vclient)
|
||
|
{
|
||
|
CClientProxy* client = reinterpret_cast<CClientProxy*>(vclient);
|
||
|
|
||
|
// find client in waiting clients queue
|
||
|
for (CWaitingClients::iterator i = m_waitingClients.begin(),
|
||
|
n = m_waitingClients.end(); i != n; ++i) {
|
||
|
if (*i == client) {
|
||
|
m_waitingClients.erase(i);
|
||
|
EVENTQUEUE->removeHandler(CClientProxy::getDisconnectedEvent(),
|
||
|
client);
|
||
|
delete client;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|