Merge remote-tracking branch 'origin/jerry-sandbox'

This commit is contained in:
XinyuHou 2015-02-10 10:28:45 +00:00
commit 3c4b6163e3
54 changed files with 1582 additions and 221 deletions

1
.gitignore vendored
View File

@ -6,6 +6,7 @@ config.h
/ext/cryptopp562 /ext/cryptopp562
/ext/gmock-1.6.0 /ext/gmock-1.6.0
/ext/gtest-1.6.0 /ext/gtest-1.6.0
/ext/openssl
/src/gui/Makefile* /src/gui/Makefile*
/src/gui/object_script* /src/gui/object_script*
/src/gui/tmp /src/gui/tmp

View File

@ -76,7 +76,7 @@ if (UNIX)
# warnings as errors: # warnings as errors:
# we have a problem with people checking in code with warnings. # we have a problem with people checking in code with warnings.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror -fPIC")
# For config.h, detect the libraries, functions, etc. # For config.h, detect the libraries, functions, etc.
include(CheckIncludeFiles) include(CheckIncludeFiles)
@ -174,7 +174,7 @@ if (UNIX)
CACHE STRING "" FORCE) CACHE STRING "" FORCE)
else() else()
# >= 10.6: Intel only # >= 10.6: Intel only
set(CMAKE_OSX_ARCHITECTURES "i386;x86_64" set(CMAKE_OSX_ARCHITECTURES "i386"
CACHE STRING "" FORCE) CACHE STRING "" FORCE)
endif() endif()

BIN
ext/openssl-1.0.1h.zip Normal file

Binary file not shown.

View File

@ -16,7 +16,6 @@
add_subdirectory(lib) add_subdirectory(lib)
add_subdirectory(cmd) add_subdirectory(cmd)
add_subdirectory(plugin)
add_subdirectory(micro) add_subdirectory(micro)
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "IRIX") if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "IRIX")

View File

@ -23,9 +23,11 @@ add_subdirectory(ipc)
add_subdirectory(mt) add_subdirectory(mt)
add_subdirectory(net) add_subdirectory(net)
add_subdirectory(platform) add_subdirectory(platform)
add_subdirectory(plugin)
add_subdirectory(server) add_subdirectory(server)
add_subdirectory(synergy) add_subdirectory(synergy)
if (WIN32) if (WIN32)
add_subdirectory(synwinhk) add_subdirectory(synwinhk)
endif() endif()

View File

@ -30,6 +30,11 @@ Arch::Arch()
s_instance = this; s_instance = this;
} }
Arch::Arch(Arch* arch)
{
s_instance = arch;
}
Arch::~Arch() Arch::~Arch()
{ {
#if SYSAPI_WIN32 #if SYSAPI_WIN32

View File

@ -99,6 +99,7 @@ class Arch : public ARCH_CONSOLE,
public ARCH_TIME { public ARCH_TIME {
public: public:
Arch(); Arch();
Arch(Arch* arch);
virtual ~Arch(); virtual ~Arch();
//! Call init on other arch classes. //! Call init on other arch classes.

View File

@ -50,5 +50,5 @@ endif()
add_library(arch STATIC ${sources}) add_library(arch STATIC ${sources})
if (UNIX) if (UNIX)
target_link_libraries(arch ${libs}) target_link_libraries(arch dl ${libs})
endif() endif()

View File

@ -21,6 +21,8 @@
#define PLUGINS_DIR "plugins" #define PLUGINS_DIR "plugins"
#include "common/IInterface.h" #include "common/IInterface.h"
#include "common/stdmap.h"
#include "base/String.h"
class IEventQueue; class IEventQueue;
@ -34,11 +36,46 @@ public:
//! @name manipulators //! @name manipulators
//@{ //@{
//! Load plugins //!Load plugins
/*! /*!
Scan the plugins dir and load plugins. Scan the plugins dir and load plugins.
*/ */
virtual void init(void* eventTarget, IEventQueue* events) = 0; virtual void load() = 0;
//!Unload plugins
/*!
Look through the loaded plugins and unload them.
*/
virtual void unload() = 0;
//! Init the common parts
/*!
Initializes common parts like log and arch.
*/
virtual void init(void* log, void* arch) = 0;
//! Init the event part
/*!
Initializes event parts.
*/
virtual void initEvent(void* eventTarget, IEventQueue* events) = 0;
//! Check if exists
/*!
Returns true if the plugin exists and is loaded.
*/
virtual bool exists(const char* name) = 0;
//! Invoke function
/*!
Invokes a function from the plugin.
*/
virtual void* invoke(const char* plugin,
const char* command,
void** args) = 0;
//@} //@}
protected:
typedef std::map<String, void*> PluginTable;
}; };

View File

@ -18,6 +18,24 @@
#include "arch/unix/ArchPluginUnix.h" #include "arch/unix/ArchPluginUnix.h"
#include "arch/unix/XArchUnix.h"
#include "base/IEventQueue.h"
#include "base/Event.h"
#include "base/Log.h"
#include <vector>
#include <sys/types.h>
#include <dirent.h>
#include <dlfcn.h>
typedef void (*initFunc)(void*, void*);
typedef int (*initEventFunc)(void (*sendEvent)(const char*, void*));
typedef void* (*invokeFunc)(const char*, void*);
typedef void (*cleanupFunc)();
void* g_eventTarget = NULL;
IEventQueue* g_events = NULL;
ArchPluginUnix::ArchPluginUnix() ArchPluginUnix::ArchPluginUnix()
{ {
} }
@ -27,6 +45,153 @@ ArchPluginUnix::~ArchPluginUnix()
} }
void void
ArchPluginUnix::init(void* eventTarget, IEventQueue* events) ArchPluginUnix::load()
{ {
String pluginsDir = getPluginsDir();
LOG((CLOG_DEBUG "plugins dir: %s", pluginsDir.c_str()));
struct dirent* de = NULL;
DIR* dir = NULL;
dir = opendir(pluginsDir.c_str());
if (dir == NULL) {
LOG((CLOG_DEBUG "can't open plugins dir: %s",
pluginsDir.c_str()));
return;
}
std::vector<String> plugins;
while ((de = readdir(dir)) != NULL) {
// ignore hidden files and diretories like .. and .
if (de->d_name[0] != '.') {
LOG((CLOG_DEBUG "load plugin %s", de->d_name));
plugins.push_back(de->d_name);
}
}
closedir(dir);
std::vector<String>::iterator it;
for (it = plugins.begin(); it != plugins.end(); ++it) {
LOG((CLOG_DEBUG "loading plugin: %s", (*it).c_str()));
String path = String(getPluginsDir()).append("/").append(*it);
void* library = dlopen(path.c_str(), RTLD_LAZY);
if (library == NULL) {
throw XArch(dlerror());
}
String filename = synergy::string::removeFileExt(*it);
m_pluginTable.insert(std::make_pair(filename, library));
}
} }
void
ArchPluginUnix::unload()
{
PluginTable::iterator it;
for (it = m_pluginTable.begin(); it != m_pluginTable.end(); it++) {
cleanupFunc cleanup = (cleanupFunc)dlsym(it->second, "cleanup");
if (cleanup != NULL) {
cleanup();
}
else {
LOG((CLOG_DEBUG "no cleanup function in %s", it->first.c_str()));
}
LOG((CLOG_DEBUG "unloading plugin: %s", it->first.c_str()));
dlclose(it->second);
}
}
void
ArchPluginUnix::init(void* log, void* arch)
{
PluginTable::iterator it;
for (it = m_pluginTable.begin(); it != m_pluginTable.end(); it++) {
initFunc initPlugin = (initFunc)dlsym(it->second, "init");
if (initPlugin != NULL) {
initPlugin(log, arch);
}
else {
LOG((CLOG_DEBUG "no init function in %s", it->first.c_str()));
}
}
}
void
ArchPluginUnix::initEvent(void* eventTarget, IEventQueue* events)
{
g_eventTarget = eventTarget;
g_events = events;
PluginTable::iterator it;
for (it = m_pluginTable.begin(); it != m_pluginTable.end(); it++) {
initEventFunc initEventPlugin = (initEventFunc)dlsym(it->second, "initEvent");
if (initEventPlugin != NULL) {
initEventPlugin(&sendEvent);
}
else {
LOG((CLOG_DEBUG "no init event function in %s", it->first.c_str()));
}
}
}
bool
ArchPluginUnix::exists(const char* name)
{
PluginTable::iterator it;
it = m_pluginTable.find(name);
return it != m_pluginTable.end() ? true : false;
}
void*
ArchPluginUnix::invoke(
const char* plugin,
const char* command,
void** args)
{
PluginTable::iterator it;
it = m_pluginTable.find(plugin);
if (it != m_pluginTable.end()) {
invokeFunc invokePlugin = (invokeFunc)dlsym(it->second, "invoke");
void* result = NULL;
if (invokePlugin != NULL) {
result = invokePlugin(command, args);
}
else {
LOG((CLOG_DEBUG "no invoke function in %s", it->first.c_str()));
}
return result;
}
else {
LOG((CLOG_DEBUG "invoke command failed, plugin: %s command: %s",
plugin, command));
return NULL;
}
}
String
ArchPluginUnix::getPluginsDir()
{
#if WINAPI_XWINDOWS
return "/usr/lib/synergy/plugin";
#else
// TODO: pluging should be in bundle in the final release
return "/Users/xinyu/Projects/synergy/bin/plugins";
#endif
}
void
sendEvent(const char* eventName, void* data)
{
LOG((CLOG_DEBUG5 "plugin sending event"));
Event::Type type = g_events->getRegisteredType(eventName);
g_events->addEvent(Event(type, g_eventTarget, data));
}
void
log(const char* text)
{
LOG((CLOG_DEBUG "plugin: %s", text));
}

View File

@ -31,5 +31,21 @@ public:
virtual ~ArchPluginUnix(); virtual ~ArchPluginUnix();
// IArchPlugin overrides // IArchPlugin overrides
void init(void* eventTarget, IEventQueue* events); void load();
void unload();
void init(void* log, void* arch);
void initEvent(void* eventTarget, IEventQueue* events);
bool exists(const char* name);
virtual void* invoke(const char* pluginName,
const char* functionName,
void** args);
private:
String getPluginsDir();
private:
PluginTable m_pluginTable;
}; };
void sendEvent(const char* text, void* data);
void log(const char* text);

View File

@ -27,7 +27,10 @@
#include <Windows.h> #include <Windows.h>
#include <iostream> #include <iostream>
typedef int (*initFunc)(void (*sendEvent)(const char*, void*), void (*log)(const char*)); typedef void (*initFunc)(void*, void*);
typedef int (*initEventFunc)(void (*sendEvent)(const char*, void*));
typedef void* (*invokeFunc)(const char*, void**);
typedef void (*cleanupFunc)();
void* g_eventTarget = NULL; void* g_eventTarget = NULL;
IEventQueue* g_events = NULL; IEventQueue* g_events = NULL;
@ -41,11 +44,8 @@ ArchPluginWindows::~ArchPluginWindows()
} }
void void
ArchPluginWindows::init(void* eventTarget, IEventQueue* events) ArchPluginWindows::load()
{ {
g_eventTarget = eventTarget;
g_events = events;
String dir = getPluginsDir(); String dir = getPluginsDir();
LOG((CLOG_DEBUG "plugins dir: %s", dir.c_str())); LOG((CLOG_DEBUG "plugins dir: %s", dir.c_str()));
@ -54,21 +54,113 @@ ArchPluginWindows::init(void* eventTarget, IEventQueue* events)
getFilenames(pattern, plugins); getFilenames(pattern, plugins);
std::vector<String>::iterator it; std::vector<String>::iterator it;
for (it = plugins.begin(); it != plugins.end(); ++it) for (it = plugins.begin(); it != plugins.end(); ++it) {
load(*it); LOG((CLOG_DEBUG "loading plugin: %s", (*it).c_str()));
String path = String(getPluginsDir()).append("\\").append(*it);
HINSTANCE library = LoadLibrary(path.c_str());
if (library == NULL) {
throw XArch(new XArchEvalWindows);
}
void* lib = reinterpret_cast<void*>(library);
String filename = synergy::string::removeFileExt(*it);
m_pluginTable.insert(std::make_pair(filename, lib));
}
} }
void void
ArchPluginWindows::load(const String& dllFilename) ArchPluginWindows::unload()
{ {
LOG((CLOG_DEBUG "loading plugin: %s", dllFilename.c_str())); PluginTable::iterator it;
String path = String(getPluginsDir()).append("\\").append(dllFilename); HINSTANCE lib;
HINSTANCE library = LoadLibrary(path.c_str()); for (it = m_pluginTable.begin(); it != m_pluginTable.end(); it++) {
if (library == NULL) lib = reinterpret_cast<HINSTANCE>(it->second);
throw XArch(new XArchEvalWindows); cleanupFunc cleanup = (cleanupFunc)GetProcAddress(lib, "cleanup");
if (cleanup != NULL) {
cleanup();
}
else {
LOG((CLOG_DEBUG "no cleanup function in %s", it->first.c_str()));
}
initFunc initPlugin = (initFunc)GetProcAddress(library, "init"); LOG((CLOG_DEBUG "unloading plugin: %s", it->first.c_str()));
initPlugin(&sendEvent, &log); FreeLibrary(lib);
}
}
void
ArchPluginWindows::init(void* log, void* arch)
{
PluginTable::iterator it;
HINSTANCE lib;
for (it = m_pluginTable.begin(); it != m_pluginTable.end(); it++) {
lib = reinterpret_cast<HINSTANCE>(it->second);
initFunc initPlugin = (initFunc)GetProcAddress(lib, "init");
if (initPlugin != NULL) {
initPlugin(log, arch);
}
else {
LOG((CLOG_DEBUG "no init function in %s", it->first.c_str()));
}
}
}
void
ArchPluginWindows::initEvent(void* eventTarget, IEventQueue* events)
{
g_eventTarget = eventTarget;
g_events = events;
PluginTable::iterator it;
HINSTANCE lib;
for (it = m_pluginTable.begin(); it != m_pluginTable.end(); it++) {
lib = reinterpret_cast<HINSTANCE>(it->second);
initEventFunc initEventPlugin = (initEventFunc)GetProcAddress(lib, "initEvent");
if (initEventPlugin != NULL) {
initEventPlugin(&sendEvent);
}
else {
LOG((CLOG_DEBUG "no init event function in %s", it->first.c_str()));
}
}
}
bool
ArchPluginWindows::exists(const char* name)
{
PluginTable::iterator it;
it = m_pluginTable.find(name);
return it != m_pluginTable.end() ? true : false;
}
void*
ArchPluginWindows::invoke(
const char* plugin,
const char* command,
void** args)
{
PluginTable::iterator it;
it = m_pluginTable.find(plugin);
if (it != m_pluginTable.end()) {
HINSTANCE lib = reinterpret_cast<HINSTANCE>(it->second);
invokeFunc invokePlugin = (invokeFunc)GetProcAddress(lib, "invoke");
void* result = NULL;
if (invokePlugin != NULL) {
result = invokePlugin(command, args);
}
else {
LOG((CLOG_DEBUG "no invoke function in %s", it->first.c_str()));
}
return result;
}
else {
LOG((CLOG_DEBUG "invoke command failed, plugin: %s command: %s",
plugin, command));
return NULL;
}
} }
String String

View File

@ -19,7 +19,6 @@
#pragma once #pragma once
#include "arch/IArchPlugin.h" #include "arch/IArchPlugin.h"
#include "base/String.h"
#include <vector> #include <vector>
@ -35,13 +34,22 @@ public:
virtual ~ArchPluginWindows(); virtual ~ArchPluginWindows();
// IArchPlugin overrides // IArchPlugin overrides
void init(void* eventTarget, IEventQueue* events); void load();
void unload();
void init(void* log, void* arch);
void initEvent(void* eventTarget, IEventQueue* events);
bool exists(const char* name);
void* invoke(const char* pluginName,
const char* functionName,
void** args);
private: private:
String getModuleDir(); String getModuleDir();
void getFilenames(const String& pattern, std::vector<String>& filenames); void getFilenames(const String& pattern, std::vector<String>& filenames);
void load(const String& dllPath);
String getPluginsDir(); String getPluginsDir();
private:
PluginTable m_pluginTable;
}; };
void sendEvent(const char* text, void* data); void sendEvent(const char* text, void* data);

View File

@ -74,6 +74,11 @@ Log::Log()
s_log = this; s_log = this;
} }
Log::Log(Log* src)
{
s_log = src;
}
Log::~Log() Log::~Log()
{ {
// clean up // clean up

View File

@ -41,6 +41,7 @@ LOGC() provide convenient access.
class Log { class Log {
public: public:
Log(); Log();
Log(Log* src);
~Log(); ~Log();
//! @name manipulators //! @name manipulators

View File

@ -168,6 +168,17 @@ findReplaceAll(
} }
} }
String
removeFileExt(String filename)
{
size_t dot = filename.find_last_of('.');
if (dot == String::npos) {
return filename;
}
return filename.substr(0, dot);
}
// //
// CaselessCmp // CaselessCmp

View File

@ -64,6 +64,12 @@ Finds \c find inside \c subject and replaces it with \c replace
*/ */
void findReplaceAll(String& subject, const String& find, const String& replace); void findReplaceAll(String& subject, const String& find, const String& replace);
//! Remove file extension
/*!
Finds the last dot and remove all characters from the dot to the end
*/
String removeFileExt(String filename);
//! Case-insensitive comparisons //! Case-insensitive comparisons
/*! /*!
This class provides case-insensitve comparison functions. This class provides case-insensitve comparison functions.

View File

@ -18,6 +18,7 @@
#include "client/Client.h" #include "client/Client.h"
#include "../plugin/ns/SecureSocket.h"
#include "client/ServerProxy.h" #include "client/ServerProxy.h"
#include "synergy/Screen.h" #include "synergy/Screen.h"
#include "synergy/Clipboard.h" #include "synergy/Clipboard.h"
@ -29,8 +30,8 @@
#include "synergy/FileChunker.h" #include "synergy/FileChunker.h"
#include "synergy/IPlatformScreen.h" #include "synergy/IPlatformScreen.h"
#include "mt/Thread.h" #include "mt/Thread.h"
#include "io/IStreamFilterFactory.h"
#include "io/CryptoStream.h" #include "io/CryptoStream.h"
#include "net/TCPSocket.h"
#include "net/IDataSocket.h" #include "net/IDataSocket.h"
#include "net/ISocketFactory.h" #include "net/ISocketFactory.h"
#include "arch/Arch.h" #include "arch/Arch.h"
@ -45,6 +46,12 @@
#include <sstream> #include <sstream>
#include <fstream> #include <fstream>
#if defined _WIN32
static const char s_networkSecurity[] = { "ns" };
#else
static const char s_networkSecurity[] = { "libns" };
#endif
// //
// Client // Client
// //
@ -53,7 +60,6 @@ Client::Client(
IEventQueue* events, IEventQueue* events,
const String& name, const NetworkAddress& address, const String& name, const NetworkAddress& address,
ISocketFactory* socketFactory, ISocketFactory* socketFactory,
IStreamFilterFactory* streamFilterFactory,
synergy::Screen* screen, synergy::Screen* screen,
const CryptoOptions& crypto, const CryptoOptions& crypto,
bool enableDragDrop) : bool enableDragDrop) :
@ -61,7 +67,6 @@ Client::Client(
m_name(name), m_name(name),
m_serverAddress(address), m_serverAddress(address),
m_socketFactory(socketFactory), m_socketFactory(socketFactory),
m_streamFilterFactory(streamFilterFactory),
m_screen(screen), m_screen(screen),
m_stream(NULL), m_stream(NULL),
m_timer(NULL), m_timer(NULL),
@ -75,7 +80,9 @@ Client::Client(
m_crypto(crypto), m_crypto(crypto),
m_sendFileThread(NULL), m_sendFileThread(NULL),
m_writeToDropDirThread(NULL), m_writeToDropDirThread(NULL),
m_enableDragDrop(enableDragDrop) m_enableDragDrop(enableDragDrop),
m_socket(NULL),
m_useSecureNetwork(false)
{ {
assert(m_socketFactory != NULL); assert(m_socketFactory != NULL);
assert(m_screen != NULL); assert(m_screen != NULL);
@ -118,7 +125,6 @@ Client::~Client()
cleanupConnecting(); cleanupConnecting();
cleanupConnection(); cleanupConnection();
delete m_socketFactory; delete m_socketFactory;
delete m_streamFilterFactory;
} }
void void
@ -150,14 +156,14 @@ Client::connect()
} }
// create the socket // create the socket
IDataSocket* socket = m_socketFactory->create(); m_useSecureNetwork = ARCH->plugin().exists(s_networkSecurity);
IDataSocket* socket = m_socketFactory->create(m_useSecureNetwork);
m_socket = dynamic_cast<TCPSocket*>(socket);
// filter socket messages, including a packetizing filter // filter socket messages, including a packetizing filter
m_stream = socket; m_stream = socket;
if (m_streamFilterFactory != NULL) { bool adopt = !m_useSecureNetwork;
m_stream = m_streamFilterFactory->create(m_stream, true); m_stream = new PacketStreamFilter(m_events, m_stream, adopt);
}
m_stream = new PacketStreamFilter(m_events, m_stream, true);
if (m_crypto.m_mode != kDisabled) { if (m_crypto.m_mode != kDisabled) {
m_cryptoStream = new CryptoStream( m_cryptoStream = new CryptoStream(
@ -174,8 +180,7 @@ Client::connect()
catch (XBase& e) { catch (XBase& e) {
cleanupTimer(); cleanupTimer();
cleanupConnecting(); cleanupConnecting();
delete m_stream; cleanupStream();
m_stream = NULL;
LOG((CLOG_DEBUG1 "connection failed")); LOG((CLOG_DEBUG1 "connection failed"));
sendConnectionFailedEvent(e.what()); sendConnectionFailedEvent(e.what());
return; return;
@ -532,8 +537,7 @@ Client::cleanupConnection()
m_stream->getEventTarget()); m_stream->getEventTarget());
m_events->removeHandler(m_events->forISocket().disconnected(), m_events->removeHandler(m_events->forISocket().disconnected(),
m_stream->getEventTarget()); m_stream->getEventTarget());
delete m_stream; cleanupStream();
m_stream = NULL;
} }
} }
@ -564,6 +568,20 @@ Client::cleanupTimer()
} }
} }
void
Client::cleanupStream()
{
delete m_stream;
m_stream = NULL;
// PacketStreamFilter doen't adopt secure socket, because
// we need to tell the dynamic lib that allocated this object
// to do the deletion.
if (m_useSecureNetwork) {
ARCH->plugin().invoke(s_networkSecurity, "deleteSocket", NULL);
}
}
void void
Client::handleConnected(const Event&, void*) Client::handleConnected(const Event&, void*)
{ {
@ -577,6 +595,8 @@ Client::handleConnected(const Event&, void*)
m_sentClipboard[id] = false; m_sentClipboard[id] = false;
m_timeClipboard[id] = 0; m_timeClipboard[id] = 0;
} }
m_socket->secureConnect();
} }
void void
@ -587,8 +607,7 @@ Client::handleConnectionFailed(const Event& event, void*)
cleanupTimer(); cleanupTimer();
cleanupConnecting(); cleanupConnecting();
delete m_stream; cleanupStream();
m_stream = NULL;
LOG((CLOG_DEBUG1 "connection failed")); LOG((CLOG_DEBUG1 "connection failed"));
sendConnectionFailedEvent(info->m_what.c_str()); sendConnectionFailedEvent(info->m_what.c_str());
delete info; delete info;
@ -600,8 +619,7 @@ Client::handleConnectTimeout(const Event&, void*)
cleanupTimer(); cleanupTimer();
cleanupConnecting(); cleanupConnecting();
cleanupConnection(); cleanupConnection();
delete m_stream; cleanupStream();
m_stream = NULL;
LOG((CLOG_DEBUG1 "connection timed out")); LOG((CLOG_DEBUG1 "connection timed out"));
sendConnectionFailedEvent("Timed out"); sendConnectionFailedEvent("Timed out");
} }

View File

@ -33,10 +33,10 @@ class ServerProxy;
class IDataSocket; class IDataSocket;
class ISocketFactory; class ISocketFactory;
namespace synergy { class IStream; } namespace synergy { class IStream; }
class IStreamFilterFactory;
class IEventQueue; class IEventQueue;
class CryptoStream; class CryptoStream;
class Thread; class Thread;
class TCPSocket;
//! Synergy client //! Synergy client
/*! /*!
@ -60,7 +60,6 @@ public:
Client(IEventQueue* events, Client(IEventQueue* events,
const String& name, const NetworkAddress& address, const String& name, const NetworkAddress& address,
ISocketFactory* socketFactory, ISocketFactory* socketFactory,
IStreamFilterFactory* streamFilterFactory,
synergy::Screen* screen, synergy::Screen* screen,
const CryptoOptions& crypto, const CryptoOptions& crypto,
bool enableDragDrop); bool enableDragDrop);
@ -189,6 +188,7 @@ private:
void cleanupConnection(); void cleanupConnection();
void cleanupScreen(); void cleanupScreen();
void cleanupTimer(); void cleanupTimer();
void cleanupStream();
void handleConnected(const Event&, void*); void handleConnected(const Event&, void*);
void handleConnectionFailed(const Event&, void*); void handleConnectionFailed(const Event&, void*);
void handleConnectTimeout(const Event&, void*); void handleConnectTimeout(const Event&, void*);
@ -210,7 +210,6 @@ private:
String m_name; String m_name;
NetworkAddress m_serverAddress; NetworkAddress m_serverAddress;
ISocketFactory* m_socketFactory; ISocketFactory* m_socketFactory;
IStreamFilterFactory* m_streamFilterFactory;
synergy::Screen* m_screen; synergy::Screen* m_screen;
synergy::IStream* m_stream; synergy::IStream* m_stream;
EventQueueTimer* m_timer; EventQueueTimer* m_timer;
@ -233,4 +232,6 @@ private:
Thread* m_sendFileThread; Thread* m_sendFileThread;
Thread* m_writeToDropDirThread; Thread* m_writeToDropDirThread;
bool m_enableDragDrop; bool m_enableDragDrop;
TCPSocket* m_socket;
bool m_useSecureNetwork;
}; };

View File

@ -49,13 +49,13 @@ public:
virtual bool isReady() const; virtual bool isReady() const;
virtual UInt32 getSize() const; virtual UInt32 getSize() const;
protected:
//! Get the stream //! Get the stream
/*! /*!
Returns the stream passed to the c'tor. Returns the stream passed to the c'tor.
*/ */
synergy::IStream* getStream() const; synergy::IStream* getStream() const;
protected:
//! Handle events from source stream //! Handle events from source stream
/*! /*!
Does the event filtering. The default simply dispatches an event Does the event filtering. The default simply dispatches an event

View File

@ -58,7 +58,7 @@ private:
private: private:
NetworkAddress m_serverAddress; NetworkAddress m_serverAddress;
CTCPSocket m_socket; TCPSocket m_socket;
IpcServerProxy* m_server; IpcServerProxy* m_server;
IEventQueue* m_events; IEventQueue* m_events;
}; };

View File

@ -18,6 +18,7 @@
#include "mt/Thread.h" #include "mt/Thread.h"
#include "net/XSocket.h"
#include "mt/XMT.h" #include "mt/XMT.h"
#include "mt/XThread.h" #include "mt/XThread.h"
#include "arch/Arch.h" #include "arch/Arch.h"
@ -158,6 +159,10 @@ Thread::threadFunc(void* vjob)
LOG((CLOG_DEBUG1 "thread 0x%08x exit", id)); LOG((CLOG_DEBUG1 "thread 0x%08x exit", id));
} }
catch (XSocket& e) {
// client called cancel()
LOG((CLOG_DEBUG "%s", e.what()));
}
catch (XThreadCancel&) { catch (XThreadCancel&) {
// client called cancel() // client called cancel()
LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id)); LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id));

View File

@ -39,7 +39,15 @@ public:
data stream. Returns NULL if no socket is waiting to be accepted. data stream. Returns NULL if no socket is waiting to be accepted.
This is only valid after a call to \c bind(). This is only valid after a call to \c bind().
*/ */
virtual IDataSocket* accept() = 0; virtual IDataSocket*
accept() = 0;
//! Delete connection socket
/*!
This is used when the socket was created but not adopted by a client
proxy.
*/
virtual void deleteSocket(void*) = 0;
//@} //@}

View File

@ -34,10 +34,10 @@ public:
//@{ //@{
//! Create data socket //! Create data socket
virtual IDataSocket* create() const = 0; virtual IDataSocket* create(bool secure) const = 0;
//! Create listen socket //! Create listen socket
virtual IListenSocket* createListen() const = 0; virtual IListenSocket* createListen(bool secure) const = 0;
//@} //@}
}; };

View File

@ -106,5 +106,6 @@ private:
SocketJobs m_socketJobs; SocketJobs m_socketJobs;
SocketJobMap m_socketJobMap; SocketJobMap m_socketJobMap;
ISocketMultiplexerJob* m_cursorMark; ISocketMultiplexerJob*
m_cursorMark;
}; };

View File

@ -110,7 +110,7 @@ TCPListenSocket::accept()
{ {
IDataSocket* socket = NULL; IDataSocket* socket = NULL;
try { try {
socket = new CTCPSocket(m_events, m_socketMultiplexer, ARCH->acceptSocket(m_socket, NULL)); socket = new TCPSocket(m_events, m_socketMultiplexer, ARCH->acceptSocket(m_socket, NULL));
if (socket != NULL) { if (socket != NULL) {
m_socketMultiplexer->addSocket(this, m_socketMultiplexer->addSocket(this,
new TSocketMultiplexerMethodJob<TCPListenSocket>( new TSocketMultiplexerMethodJob<TCPListenSocket>(

View File

@ -33,7 +33,7 @@ A listen socket using TCP.
class TCPListenSocket : public IListenSocket { class TCPListenSocket : public IListenSocket {
public: public:
TCPListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer); TCPListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer);
~TCPListenSocket(); virtual ~TCPListenSocket();
// ISocket overrides // ISocket overrides
virtual void bind(const NetworkAddress&); virtual void bind(const NetworkAddress&);
@ -41,14 +41,16 @@ public:
virtual void* getEventTarget() const; virtual void* getEventTarget() const;
// IListenSocket overrides // IListenSocket overrides
virtual IDataSocket* accept(); virtual IDataSocket*
accept();
virtual void deleteSocket(void*) { }
private: public:
ISocketMultiplexerJob* ISocketMultiplexerJob*
serviceListening(ISocketMultiplexerJob*, serviceListening(ISocketMultiplexerJob*,
bool, bool, bool); bool, bool, bool);
private: protected:
ArchSocket m_socket; ArchSocket m_socket;
Mutex* m_mutex; Mutex* m_mutex;
IEventQueue* m_events; IEventQueue* m_events;

View File

@ -34,10 +34,10 @@
#include <memory> #include <memory>
// //
// CTCPSocket // TCPSocket
// //
CTCPSocket::CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer) :
IDataSocket(events), IDataSocket(events),
m_mutex(), m_mutex(),
m_flushed(&m_mutex, true), m_flushed(&m_mutex, true),
@ -54,7 +54,7 @@ CTCPSocket::CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer
init(); init();
} }
CTCPSocket::CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket) : TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket) :
IDataSocket(events), IDataSocket(events),
m_mutex(), m_mutex(),
m_socket(socket), m_socket(socket),
@ -70,7 +70,7 @@ CTCPSocket::CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer
setJob(newJob()); setJob(newJob());
} }
CTCPSocket::~CTCPSocket() TCPSocket::~TCPSocket()
{ {
try { try {
close(); close();
@ -81,7 +81,7 @@ CTCPSocket::~CTCPSocket()
} }
void void
CTCPSocket::bind(const NetworkAddress& addr) TCPSocket::bind(const NetworkAddress& addr)
{ {
try { try {
ARCH->bindSocket(m_socket, addr.getAddress()); ARCH->bindSocket(m_socket, addr.getAddress());
@ -95,7 +95,7 @@ CTCPSocket::bind(const NetworkAddress& addr)
} }
void void
CTCPSocket::close() TCPSocket::close()
{ {
// remove ourself from the multiplexer // remove ourself from the multiplexer
setJob(NULL); setJob(NULL);
@ -123,13 +123,13 @@ CTCPSocket::close()
} }
void* void*
CTCPSocket::getEventTarget() const TCPSocket::getEventTarget() const
{ {
return const_cast<void*>(reinterpret_cast<const void*>(this)); return const_cast<void*>(reinterpret_cast<const void*>(this));
} }
UInt32 UInt32
CTCPSocket::read(void* buffer, UInt32 n) TCPSocket::read(void* buffer, UInt32 n)
{ {
// copy data directly from our input buffer // copy data directly from our input buffer
Lock lock(&m_mutex); Lock lock(&m_mutex);
@ -152,7 +152,7 @@ CTCPSocket::read(void* buffer, UInt32 n)
} }
void void
CTCPSocket::write(const void* buffer, UInt32 n) TCPSocket::write(const void* buffer, UInt32 n)
{ {
bool wasEmpty; bool wasEmpty;
{ {
@ -184,7 +184,7 @@ CTCPSocket::write(const void* buffer, UInt32 n)
} }
void void
CTCPSocket::flush() TCPSocket::flush()
{ {
Lock lock(&m_mutex); Lock lock(&m_mutex);
while (m_flushed == false) { while (m_flushed == false) {
@ -193,7 +193,7 @@ CTCPSocket::flush()
} }
void void
CTCPSocket::shutdownInput() TCPSocket::shutdownInput()
{ {
bool useNewJob = false; bool useNewJob = false;
{ {
@ -220,7 +220,7 @@ CTCPSocket::shutdownInput()
} }
void void
CTCPSocket::shutdownOutput() TCPSocket::shutdownOutput()
{ {
bool useNewJob = false; bool useNewJob = false;
{ {
@ -247,21 +247,21 @@ CTCPSocket::shutdownOutput()
} }
bool bool
CTCPSocket::isReady() const TCPSocket::isReady() const
{ {
Lock lock(&m_mutex); Lock lock(&m_mutex);
return (m_inputBuffer.getSize() > 0); return (m_inputBuffer.getSize() > 0);
} }
UInt32 UInt32
CTCPSocket::getSize() const TCPSocket::getSize() const
{ {
Lock lock(&m_mutex); Lock lock(&m_mutex);
return m_inputBuffer.getSize(); return m_inputBuffer.getSize();
} }
void void
CTCPSocket::connect(const NetworkAddress& addr) TCPSocket::connect(const NetworkAddress& addr)
{ {
{ {
Lock lock(&m_mutex); Lock lock(&m_mutex);
@ -290,7 +290,7 @@ CTCPSocket::connect(const NetworkAddress& addr)
} }
void void
CTCPSocket::init() TCPSocket::init()
{ {
// default state // default state
m_connected = false; m_connected = false;
@ -316,7 +316,7 @@ CTCPSocket::init()
} }
void void
CTCPSocket::setJob(ISocketMultiplexerJob* job) TCPSocket::setJob(ISocketMultiplexerJob* job)
{ {
// multiplexer will delete the old job // multiplexer will delete the old job
if (job == NULL) { if (job == NULL) {
@ -328,7 +328,7 @@ CTCPSocket::setJob(ISocketMultiplexerJob* job)
} }
ISocketMultiplexerJob* ISocketMultiplexerJob*
CTCPSocket::newJob() TCPSocket::newJob()
{ {
// note -- must have m_mutex locked on entry // note -- must have m_mutex locked on entry
@ -340,23 +340,23 @@ CTCPSocket::newJob()
if (!(m_readable || m_writable)) { if (!(m_readable || m_writable)) {
return NULL; return NULL;
} }
return new TSocketMultiplexerMethodJob<CTCPSocket>( return new TSocketMultiplexerMethodJob<TCPSocket>(
this, &CTCPSocket::serviceConnecting, this, &TCPSocket::serviceConnecting,
m_socket, m_readable, m_writable); m_socket, m_readable, m_writable);
} }
else { else {
if (!(m_readable || (m_writable && (m_outputBuffer.getSize() > 0)))) { if (!(m_readable || (m_writable && (m_outputBuffer.getSize() > 0)))) {
return NULL; return NULL;
} }
return new TSocketMultiplexerMethodJob<CTCPSocket>( return new TSocketMultiplexerMethodJob<TCPSocket>(
this, &CTCPSocket::serviceConnected, this, &TCPSocket::serviceConnected,
m_socket, m_readable, m_socket, m_readable,
m_writable && (m_outputBuffer.getSize() > 0)); m_writable && (m_outputBuffer.getSize() > 0));
} }
} }
void void
CTCPSocket::sendConnectionFailedEvent(const char* msg) TCPSocket::sendConnectionFailedEvent(const char* msg)
{ {
ConnectionFailedInfo* info = new ConnectionFailedInfo(msg); ConnectionFailedInfo* info = new ConnectionFailedInfo(msg);
m_events->addEvent(Event(m_events->forIDataSocket().connectionFailed(), m_events->addEvent(Event(m_events->forIDataSocket().connectionFailed(),
@ -364,13 +364,13 @@ CTCPSocket::sendConnectionFailedEvent(const char* msg)
} }
void void
CTCPSocket::sendEvent(Event::Type type) TCPSocket::sendEvent(Event::Type type)
{ {
m_events->addEvent(Event(type, getEventTarget(), NULL)); m_events->addEvent(Event(type, getEventTarget(), NULL));
} }
void void
CTCPSocket::onConnected() TCPSocket::onConnected()
{ {
m_connected = true; m_connected = true;
m_readable = true; m_readable = true;
@ -378,14 +378,14 @@ CTCPSocket::onConnected()
} }
void void
CTCPSocket::onInputShutdown() TCPSocket::onInputShutdown()
{ {
m_inputBuffer.pop(m_inputBuffer.getSize()); m_inputBuffer.pop(m_inputBuffer.getSize());
m_readable = false; m_readable = false;
} }
void void
CTCPSocket::onOutputShutdown() TCPSocket::onOutputShutdown()
{ {
m_outputBuffer.pop(m_outputBuffer.getSize()); m_outputBuffer.pop(m_outputBuffer.getSize());
m_writable = false; m_writable = false;
@ -396,7 +396,7 @@ CTCPSocket::onOutputShutdown()
} }
void void
CTCPSocket::onDisconnected() TCPSocket::onDisconnected()
{ {
// disconnected // disconnected
onInputShutdown(); onInputShutdown();
@ -405,7 +405,7 @@ CTCPSocket::onDisconnected()
} }
ISocketMultiplexerJob* ISocketMultiplexerJob*
CTCPSocket::serviceConnecting(ISocketMultiplexerJob* job, TCPSocket::serviceConnecting(ISocketMultiplexerJob* job,
bool, bool write, bool error) bool, bool write, bool error)
{ {
Lock lock(&m_mutex); Lock lock(&m_mutex);
@ -449,7 +449,7 @@ CTCPSocket::serviceConnecting(ISocketMultiplexerJob* job,
} }
ISocketMultiplexerJob* ISocketMultiplexerJob*
CTCPSocket::serviceConnected(ISocketMultiplexerJob* job, TCPSocket::serviceConnected(ISocketMultiplexerJob* job,
bool read, bool write, bool error) bool read, bool write, bool error)
{ {
Lock lock(&m_mutex); Lock lock(&m_mutex);
@ -467,7 +467,17 @@ CTCPSocket::serviceConnected(ISocketMultiplexerJob* job,
// write data // write data
UInt32 n = m_outputBuffer.getSize(); UInt32 n = m_outputBuffer.getSize();
const void* buffer = m_outputBuffer.peek(n); const void* buffer = m_outputBuffer.peek(n);
if (isSecure()) {
if (isSecureReady()) {
n = secureWrite(buffer, n);
}
else {
return job;
}
}
else {
n = (UInt32)ARCH->writeSocket(m_socket, buffer, n); n = (UInt32)ARCH->writeSocket(m_socket, buffer, n);
}
// discard written data // discard written data
if (n > 0) { if (n > 0) {
@ -510,14 +520,34 @@ CTCPSocket::serviceConnected(ISocketMultiplexerJob* job,
if (read && m_readable) { if (read && m_readable) {
try { try {
UInt8 buffer[4096]; UInt8 buffer[4096];
size_t n = ARCH->readSocket(m_socket, buffer, sizeof(buffer)); size_t n = 0;
if (isSecure()) {
if (isSecureReady()) {
n = secureRead(buffer, sizeof(buffer));
}
else {
return job;
}
}
else {
n = ARCH->readSocket(m_socket, buffer, sizeof(buffer));
}
if (n > 0) { if (n > 0) {
bool wasEmpty = (m_inputBuffer.getSize() == 0); bool wasEmpty = (m_inputBuffer.getSize() == 0);
// slurp up as much as possible // slurp up as much as possible
do { do {
m_inputBuffer.write(buffer, (UInt32)n); m_inputBuffer.write(buffer, (UInt32)n);
if (isSecure() && isSecureReady()) {
n = secureRead(buffer, sizeof(buffer));
}
else {
n = ARCH->readSocket(m_socket, buffer, sizeof(buffer)); n = ARCH->readSocket(m_socket, buffer, sizeof(buffer));
}
} while (n > 0); } while (n > 0);
// send input ready if input buffer was empty // send input ready if input buffer was empty

View File

@ -34,11 +34,11 @@ class SocketMultiplexer;
/*! /*!
A data socket using TCP. A data socket using TCP.
*/ */
class CTCPSocket : public IDataSocket { class TCPSocket : public IDataSocket {
public: public:
CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer); TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer);
CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket); TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket);
~CTCPSocket(); virtual ~TCPSocket();
// ISocket overrides // ISocket overrides
virtual void bind(const NetworkAddress&); virtual void bind(const NetworkAddress&);
@ -57,14 +57,31 @@ public:
// IDataSocket overrides // IDataSocket overrides
virtual void connect(const NetworkAddress&); virtual void connect(const NetworkAddress&);
virtual void secureConnect() {}
virtual void secureAccept() {}
protected:
ArchSocket getSocket() { return m_socket; }
IEventQueue* getEvents() { return m_events; }
virtual bool isSecureReady() { return false; }
virtual bool isSecure() { return false; }
virtual UInt32 secureRead(void* buffer, UInt32) { return 0; }
virtual UInt32 secureWrite(const void*, UInt32) { return 0; }
void setJob(ISocketMultiplexerJob*);
ISocketMultiplexerJob*
newJob();
bool isReadable() { return m_readable; }
bool isWritable() { return m_writable; }
Mutex& getMutex() { return m_mutex; }
void sendEvent(Event::Type);
private: private:
void init(); void init();
void setJob(ISocketMultiplexerJob*);
ISocketMultiplexerJob* newJob();
void sendConnectionFailedEvent(const char*); void sendConnectionFailedEvent(const char*);
void sendEvent(Event::Type);
void onConnected(); void onConnected();
void onInputShutdown(); void onInputShutdown();
void onOutputShutdown(); void onOutputShutdown();

View File

@ -20,31 +20,65 @@
#include "net/TCPSocket.h" #include "net/TCPSocket.h"
#include "net/TCPListenSocket.h" #include "net/TCPListenSocket.h"
#include "arch/Arch.h"
#include "base/Log.h"
// //
// CTCPSocketFactory // TCPSocketFactory
// //
CTCPSocketFactory::CTCPSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : #if defined _WIN32
static const char s_networkSecurity[] = { "ns" };
#else
static const char s_networkSecurity[] = { "libns" };
#endif
TCPSocketFactory::TCPSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer) :
m_events(events), m_events(events),
m_socketMultiplexer(socketMultiplexer) m_socketMultiplexer(socketMultiplexer)
{ {
// do nothing // do nothing
} }
CTCPSocketFactory::~CTCPSocketFactory() TCPSocketFactory::~TCPSocketFactory()
{ {
// do nothing // do nothing
} }
IDataSocket* IDataSocket*
CTCPSocketFactory::create() const TCPSocketFactory::create(bool secure) const
{ {
return new CTCPSocket(m_events, m_socketMultiplexer); IDataSocket* socket = NULL;
if (secure) {
void* args[2] = {
m_events,
m_socketMultiplexer
};
socket = static_cast<IDataSocket*>(
ARCH->plugin().invoke(s_networkSecurity, "getSocket", args));
}
else {
socket = new TCPSocket(m_events, m_socketMultiplexer);
}
return socket;
} }
IListenSocket* IListenSocket*
CTCPSocketFactory::createListen() const TCPSocketFactory::createListen(bool secure) const
{ {
return new TCPListenSocket(m_events, m_socketMultiplexer); IListenSocket* socket = NULL;
if (secure) {
void* args[2] = {
m_events,
m_socketMultiplexer
};
socket = static_cast<IListenSocket*>(
ARCH->plugin().invoke(s_networkSecurity, "getListenSocket", args));
}
else {
socket = new TCPListenSocket(m_events, m_socketMultiplexer);
}
return socket;
} }

View File

@ -24,14 +24,16 @@ class IEventQueue;
class SocketMultiplexer; class SocketMultiplexer;
//! Socket factory for TCP sockets //! Socket factory for TCP sockets
class CTCPSocketFactory : public ISocketFactory { class TCPSocketFactory : public ISocketFactory {
public: public:
CTCPSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer); TCPSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer);
virtual ~CTCPSocketFactory(); virtual ~TCPSocketFactory();
// ISocketFactory overrides // ISocketFactory overrides
virtual IDataSocket* create() const; virtual IDataSocket*
virtual IListenSocket* createListen() const; create(bool secure) const;
virtual IListenSocket*
createListen(bool secure) const;
private: private:
IEventQueue* m_events; IEventQueue* m_events;

View File

@ -14,6 +14,8 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
add_subdirectory(ns)
if (WIN32) if (WIN32)
add_subdirectory(winmmjoy) add_subdirectory(winmmjoy)
endif() endif()

View File

@ -0,0 +1,93 @@
# synergy -- mouse and keyboard sharing utility
# Copyright (C) 2015 Synergy Si Ltd.
#
# 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/>.
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if (SYNERGY_ADD_HEADERS)
list(APPEND sources ${headers})
endif()
if (WIN32)
set(OPENSSL_INCLUDE ../../../../ext/openssl/inc32)
endif()
if (APPLE)
set(OPENSSL_INCLUDE ../../../../ext/openssl/include)
endif()
include_directories(
../../../lib/
../../../..
${OPENSSL_INCLUDE}
)
add_library(ns SHARED ${sources})
if (WIN32)
set(OPENSSL_LIBS
${CMAKE_SOURCE_DIR}/ext/openssl/out32dll/libeay32.lib
${CMAKE_SOURCE_DIR}/ext/openssl/out32dll/ssleay32.lib
)
endif()
if (UNIX)
if (APPLE)
set(OPENSSL_LIBS
${CMAKE_SOURCE_DIR}/ext/openssl/libssl.a
${CMAKE_SOURCE_DIR}/ext/openssl/libcrypto.a
)
else()
set(OPENSSL_LIBS ssl crypto)
endif()
endif()
target_link_libraries(ns
arch base client common io mt net ipc platform server synergy cryptopp ${libs} ${OPENSSL_LIBS})
if (WIN32)
add_custom_command(
TARGET ns
POST_BUILD
COMMAND xcopy /Y /Q
..\\..\\..\\..\\..\\lib\\${CMAKE_CFG_INTDIR}\\ns.dll
..\\..\\..\\..\\..\\bin\\${CMAKE_CFG_INTDIR}\\plugins\\
)
else()
if (APPLE)
add_custom_command(
TARGET ns
POST_BUILD
COMMAND
mkdir -p
${CMAKE_SOURCE_DIR}/bin/plugins
&&
cp
${CMAKE_SOURCE_DIR}/lib/${CMAKE_CFG_INTDIR}/libns.dylib
${CMAKE_SOURCE_DIR}/bin/plugins/
)
else()
add_custom_command(
TARGET ns
POST_BUILD
COMMAND mkdir -p
${CMAKE_SOURCE_DIR}/bin/plugins
&&
cp
${CMAKE_SOURCE_DIR}/lib/libns.so
${CMAKE_SOURCE_DIR}/bin/plugins/
)
endif()
endif()

View File

@ -0,0 +1,94 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015 Synergy Si Ltd.
*
* 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 "SecureListenSocket.h"
#include "SecureSocket.h"
#include "net/NetworkAddress.h"
#include "net/SocketMultiplexer.h"
#include "net/TSocketMultiplexerMethodJob.h"
#include "arch/XArch.h"
//
// SecureListenSocket
//
SecureListenSocket::SecureListenSocket(
IEventQueue* events,
SocketMultiplexer* socketMultiplexer) :
TCPListenSocket(events, socketMultiplexer)
{
}
SecureListenSocket::~SecureListenSocket()
{
SecureSocketSet::iterator it;
for (it = m_secureSocketSet.begin(); it != m_secureSocketSet.end(); it++) {
delete *it;
}
m_secureSocketSet.clear();
}
IDataSocket*
SecureListenSocket::accept()
{
SecureSocket* socket = NULL;
try {
socket = new SecureSocket(
m_events,
m_socketMultiplexer,
ARCH->acceptSocket(m_socket, NULL));
m_secureSocketSet.insert(socket);
socket->initSsl(true);
// TODO: customized certificate path
socket->loadCertificates("C:\\Temp\\synergy.pem");
socket->secureAccept();
if (socket != NULL) {
m_socketMultiplexer->addSocket(this,
new TSocketMultiplexerMethodJob<TCPListenSocket>(
this, &TCPListenSocket::serviceListening,
m_socket, true, false));
}
return dynamic_cast<IDataSocket*>(socket);
}
catch (XArchNetwork&) {
if (socket != NULL) {
delete socket;
}
return NULL;
}
catch (std::exception &ex) {
if (socket != NULL) {
delete socket;
}
throw ex;
}
}
void
SecureListenSocket::deleteSocket(void* socket)
{
SecureSocketSet::iterator it;
it = m_secureSocketSet.find((IDataSocket*)socket);
if (it != m_secureSocketSet.end()) {
delete *it;
m_secureSocketSet.erase(it);
}
}

View File

@ -1,7 +1,6 @@
/* /*
* synergy -- mouse and keyboard sharing utility * synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012 Synergy Si Ltd. * Copyright (C) 2015 Synergy Si Ltd.
* Copyright (C) 2002 Chris Schoeneman
* *
* This package is free software; you can redistribute it and/or * This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -18,21 +17,26 @@
#pragma once #pragma once
#include "common/IInterface.h" #include "net/TCPListenSocket.h"
#include "common/stdset.h"
namespace synergy { class IStream; } class IEventQueue;
class SocketMultiplexer;
class IDataSocket;
//! Stream filter factory interface class SecureListenSocket : public TCPListenSocket{
/*!
This interface provides factory methods to create stream filters.
*/
class IStreamFilterFactory : public IInterface {
public: public:
//! Create filter SecureListenSocket(IEventQueue* events,
/*! SocketMultiplexer* socketMultiplexer);
Create and return a stream filter on \p stream. The caller must ~SecureListenSocket();
delete the returned object.
*/ // IListenSocket overrides
virtual synergy::IStream* virtual IDataSocket*
create(synergy::IStream* stream, bool adoptStream) = 0; accept();
void deleteSocket(void*);
private:
typedef std::set<IDataSocket*> SecureSocketSet;
SecureSocketSet m_secureSocketSet;
}; };

View File

@ -0,0 +1,390 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015 Synergy Si Ltd.
*
* 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 "SecureSocket.h"
#include "net/TSocketMultiplexerMethodJob.h"
#include "net/TCPSocket.h"
#include "mt/Lock.h"
#include "arch/XArch.h"
#include "base/Log.h"
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <cstring>
#include <cstdlib>
#include <memory>
//
// SecureSocket
//
#define MAX_ERROR_SIZE 65535
struct Ssl {
SSL_CTX* m_context;
SSL* m_ssl;
};
SecureSocket::SecureSocket(
IEventQueue* events,
SocketMultiplexer* socketMultiplexer) :
TCPSocket(events, socketMultiplexer),
m_secureReady(false)
{
}
SecureSocket::SecureSocket(
IEventQueue* events,
SocketMultiplexer* socketMultiplexer,
ArchSocket socket) :
TCPSocket(events, socketMultiplexer, socket),
m_secureReady(false)
{
}
SecureSocket::~SecureSocket()
{
if (m_ssl->m_ssl != NULL) {
SSL_shutdown(m_ssl->m_ssl);
SSL_free(m_ssl->m_ssl);
m_ssl->m_ssl = NULL;
}
if (m_ssl->m_context != NULL) {
SSL_CTX_free(m_ssl->m_context);
m_ssl->m_context = NULL;
}
delete m_ssl;
delete[] m_error;
}
void
SecureSocket::close()
{
SSL_shutdown(m_ssl->m_ssl);
TCPSocket::close();
}
void
SecureSocket::secureConnect()
{
setJob(new TSocketMultiplexerMethodJob<SecureSocket>(
this, &SecureSocket::serviceConnect,
getSocket(), isReadable(), isWritable()));
}
void
SecureSocket::secureAccept()
{
setJob(new TSocketMultiplexerMethodJob<SecureSocket>(
this, &SecureSocket::serviceAccept,
getSocket(), isReadable(), isWritable()));
}
UInt32
SecureSocket::secureRead(void* buffer, UInt32 n)
{
bool retry = false;
int r = 0;
if (m_ssl->m_ssl != NULL) {
r = SSL_read(m_ssl->m_ssl, buffer, n);
retry = checkResult(r);
if (retry) {
r = 0;
}
}
return r > 0 ? (UInt32)r : 0;
}
UInt32
SecureSocket::secureWrite(const void* buffer, UInt32 n)
{
bool retry = false;
int r = 0;
if (m_ssl->m_ssl != NULL) {
r = SSL_write(m_ssl->m_ssl, buffer, n);
retry = checkResult(r);
if (retry) {
r = 0;
}
}
return r > 0 ? (UInt32)r : 0;
}
bool
SecureSocket::isSecureReady()
{
return m_secureReady;
}
void
SecureSocket::initSsl(bool server)
{
m_ssl = new Ssl();
m_ssl->m_context = NULL;
m_ssl->m_ssl = NULL;
m_error = new char[MAX_ERROR_SIZE];
initContext(server);
}
void
SecureSocket::loadCertificates(const char* filename)
{
int r = 0;
r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename, SSL_FILETYPE_PEM);
if (r <= 0) {
showError();
}
r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename, SSL_FILETYPE_PEM);
if (r <= 0) {
showError();
}
//verify private key
r = SSL_CTX_check_private_key(m_ssl->m_context);
if (!r) {
showError();
}
}
void
SecureSocket::initContext(bool server)
{
SSL_library_init();
const SSL_METHOD* method;
// load & register all cryptos, etc.
OpenSSL_add_all_algorithms();
// load all error messages
SSL_load_error_strings();
if (server) {
// create new server-method instance
method = SSLv23_server_method();
}
else {
// create new client-method instance
method = SSLv23_client_method();
}
// create new context from method
m_ssl->m_context = SSL_CTX_new(method);
if (m_ssl->m_context == NULL) {
showError();
}
}
void
SecureSocket::createSSL()
{
// I assume just one instance is needed
// get new SSL state with context
if (m_ssl->m_ssl == NULL) {
m_ssl->m_ssl = SSL_new(m_ssl->m_context);
}
}
bool
SecureSocket::secureAccept(int socket)
{
createSSL();
// set connection socket to SSL state
SSL_set_fd(m_ssl->m_ssl, socket);
// do SSL-protocol accept
LOG((CLOG_DEBUG1 "secureAccept"));
int r = SSL_accept(m_ssl->m_ssl);
bool retry = checkResult(r);
m_secureReady = !retry;
return retry;
}
bool
SecureSocket::secureConnect(int socket)
{
createSSL();
// attach the socket descriptor
SSL_set_fd(m_ssl->m_ssl, socket);
LOG((CLOG_DEBUG1 "secureConnect"));
int r = SSL_connect(m_ssl->m_ssl);
bool retry = checkResult(r);
m_secureReady = !retry;
if (m_secureReady) {
showCertificate();
}
return retry;
}
void
SecureSocket::showCertificate()
{
X509* cert;
char* line;
// get the server's certificate
cert = SSL_get_peer_certificate(m_ssl->m_ssl);
if (cert != NULL) {
LOG((CLOG_INFO "server certificate"));
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
LOG((CLOG_INFO "subject: %s", line));
OPENSSL_free(line);
X509_free(cert);
}
else {
LOG((CLOG_INFO "no certificates"));
}
}
bool
SecureSocket::checkResult(int n)
{
bool retry = false;
int errorCode = SSL_get_error(m_ssl->m_ssl, n);
switch (errorCode) {
case SSL_ERROR_NONE:
// the TLS/SSL I/O operation completed
break;
case SSL_ERROR_ZERO_RETURN:
// the TLS/SSL connection has been closed
LOG((CLOG_DEBUG2 "SSL_ERROR_ZERO_RETURN"));
break;
case SSL_ERROR_WANT_READ:
LOG((CLOG_DEBUG2 "secure socket error: SSL_ERROR_WANT_READ"));
retry = true;
break;
case SSL_ERROR_WANT_WRITE:
LOG((CLOG_DEBUG2 "secure socket error: SSL_ERROR_WANT_WRITE"));
retry = true;
break;
case SSL_ERROR_WANT_CONNECT:
LOG((CLOG_DEBUG2 "secure socket error: SSL_ERROR_WANT_CONNECT"));
retry = true;
break;
case SSL_ERROR_WANT_ACCEPT:
LOG((CLOG_DEBUG2 "secure socket error: SSL_ERROR_WANT_ACCEPT"));
retry = true;
break;
case SSL_ERROR_SYSCALL:
// some I/O error occurred
throwError("Secure socket syscall error");
break;
case SSL_ERROR_SSL:
// a failure in the SSL library occurred
LOG((CLOG_DEBUG2 "SSL_ERROR_SSL"));
sendEvent(getEvents()->forISocket().disconnected());
sendEvent(getEvents()->forIStream().inputShutdown());
showError();
retry = true;
break;
default:
// possible cases:
// SSL_ERROR_WANT_X509_LOOKUP
showError();
}
return retry;
}
void
SecureSocket::showError()
{
if (getError()) {
LOG((CLOG_ERR "secure socket error: %s", m_error));
}
}
void
SecureSocket::throwError(const char* reason)
{
if (getError()) {
throw XSocket(synergy::string::sprintf(
"%s: %s", reason, m_error));
}
}
bool
SecureSocket::getError()
{
unsigned long e = ERR_get_error();
bool errorUpdated = false;
if (e != 0) {
ERR_error_string_n(e, m_error, MAX_ERROR_SIZE);
errorUpdated = true;
}
else {
LOG((CLOG_DEBUG2 "can not detect any error in secure socket"));
}
return errorUpdated;
}
ISocketMultiplexerJob*
SecureSocket::serviceConnect(ISocketMultiplexerJob* job,
bool, bool write, bool error)
{
Lock lock(&getMutex());
bool retry = true;
#ifdef SYSAPI_WIN32
retry = secureConnect(static_cast<int>(getSocket()->m_socket));
#elif SYSAPI_UNIX
retry = secureConnect(getSocket()->m_fd);
#endif
return retry ? job : newJob();
}
ISocketMultiplexerJob*
SecureSocket::serviceAccept(ISocketMultiplexerJob* job,
bool, bool write, bool error)
{
Lock lock(&getMutex());
bool retry = true;
#ifdef SYSAPI_WIN32
retry = secureAccept(static_cast<int>(getSocket()->m_socket));
#elif SYSAPI_UNIX
retry = secureAccept(getSocket()->m_fd);
#endif
return retry ? job : newJob();
}

View File

@ -0,0 +1,78 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015 Synergy Si Ltd.
*
* 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/>.
*/
#pragma once
#include "net/TCPSocket.h"
#include "net/XSocket.h"
class IEventQueue;
class SocketMultiplexer;
class ISocketMultiplexerJob;
struct Ssl;
//! Secure socket
/*!
A secure socket using SSL.
*/
class SecureSocket : public TCPSocket {
public:
SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer);
SecureSocket(IEventQueue* events,
SocketMultiplexer* socketMultiplexer,
ArchSocket socket);
~SecureSocket();
// ISocket overrides
void close();
void secureConnect();
void secureAccept();
bool isReady() const { return m_secureReady; }
bool isSecureReady();
bool isSecure() { return true; }
UInt32 secureRead(void* buffer, UInt32 n);
UInt32 secureWrite(const void* buffer, UInt32 n);
void initSsl(bool server);
void loadCertificates(const char* CertFile);
private:
// SSL
void initContext(bool server);
void createSSL();
bool secureAccept(int s);
bool secureConnect(int s);
void showCertificate();
bool checkResult(int n);
void showError();
void throwError(const char* reason);
bool getError();
ISocketMultiplexerJob*
serviceConnect(ISocketMultiplexerJob*,
bool, bool, bool);
ISocketMultiplexerJob*
serviceAccept(ISocketMultiplexerJob*,
bool, bool, bool);
private:
Ssl* m_ssl;
bool m_secureReady;
char* m_error;
};

105
src/lib/plugin/ns/ns.cpp Normal file
View File

@ -0,0 +1,105 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015 Synergy Si Ltd
*
* 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 "ns.h"
#include "SecureSocket.h"
#include "SecureListenSocket.h"
#include "arch/Arch.h"
#include "base/Log.h"
#include <iostream>
SecureSocket* g_secureSocket = NULL;
SecureListenSocket* g_secureListenSocket = NULL;
Arch* g_arch = NULL;
Log* g_log = NULL;
extern "C" {
void
init(void* log, void* arch)
{
if (g_log == NULL) {
g_log = new Log(reinterpret_cast<Log*>(log));
}
if (g_arch == NULL) {
g_arch = new Arch(reinterpret_cast<Arch*>(arch));
}
}
int
initEvent(void (*sendEvent)(const char*, void*))
{
return 0;
}
void*
invoke(const char* command, void** args)
{
IEventQueue* arg1 = NULL;
SocketMultiplexer* arg2 = NULL;
if (args != NULL) {
arg1 = reinterpret_cast<IEventQueue*>(args[0]);
arg2 = reinterpret_cast<SocketMultiplexer*>(args[1]);
}
if (strcmp(command, "getSocket") == 0) {
if (g_secureSocket != NULL) {
delete g_secureSocket;
}
g_secureSocket = new SecureSocket(arg1, arg2);
g_secureSocket->initSsl(false);
return g_secureSocket;
}
else if (strcmp(command, "getListenSocket") == 0) {
if (g_secureListenSocket != NULL) {
delete g_secureListenSocket;
}
g_secureListenSocket = new SecureListenSocket(arg1, arg2);
return g_secureListenSocket;
}
else if (strcmp(command, "deleteSocket") == 0) {
if (g_secureSocket != NULL) {
delete g_secureSocket;
g_secureSocket = NULL;
}
}
else if (strcmp(command, "deleteListenSocket") == 0) {
if (g_secureListenSocket != NULL) {
delete g_secureListenSocket;
g_secureListenSocket = NULL;
}
}
return NULL;
}
void
cleanup()
{
if (g_secureSocket != NULL) {
delete g_secureSocket;
}
if (g_secureListenSocket != NULL) {
delete g_secureListenSocket;
}
}
}

41
src/lib/plugin/ns/ns.h Normal file
View File

@ -0,0 +1,41 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015 Synergy Si Ltd
*
* 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/>.
*/
#pragma once
#if defined _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#if defined(ns_EXPORTS)
#define NS_API __declspec(dllexport)
#else
#define NS_API __declspec(dllimport)
#endif
#else
#define NS_API
#endif
extern "C" {
NS_API void init(void* log, void* arch);
NS_API int initEvent(void (*sendEvent)(const char*, void*));
NS_API void* invoke(const char* command, void** args);
NS_API void cleanup();
}

View File

@ -27,6 +27,6 @@ add_custom_command(
TARGET winmmjoy TARGET winmmjoy
POST_BUILD POST_BUILD
COMMAND xcopy /Y /Q COMMAND xcopy /Y /Q
..\\..\\..\\..\\lib\\${CMAKE_CFG_INTDIR}\\winmmjoy.* ..\\..\\..\\..\\..\\lib\\${CMAKE_CFG_INTDIR}\\winmmjoy.*
..\\..\\..\\..\\bin\\${CMAKE_CFG_INTDIR}\\plugins\\ ..\\..\\..\\..\\..\\bin\\${CMAKE_CFG_INTDIR}\\plugins\\
) )

View File

@ -36,22 +36,23 @@ static void (*s_log)(const char*) = NULL;
extern "C" { extern "C" {
void
init(void* log, void* arch)
{
}
int int
init(void (*sendEvent)(const char*, void*), void (*log)(const char*)) initEvent(void (*sendEvent)(const char*, void*))
{ {
s_sendEvent = sendEvent; s_sendEvent = sendEvent;
s_log = log;
LOG("init");
CreateThread(NULL, 0, mainLoop, NULL, 0, NULL); CreateThread(NULL, 0, mainLoop, NULL, 0, NULL);
return 0; return 0;
} }
int void
cleanup() cleanup()
{ {
LOG("cleanup");
s_running = false; s_running = false;
return 0;
} }
} }

View File

@ -29,8 +29,9 @@
extern "C" { extern "C" {
WINMMJOY_API int init(void (*sendEvent)(const char*, void*), void (*log)(const char*)); WINMMJOY_API void init(void* log, void* arch);
WINMMJOY_API int cleanup(); WINMMJOY_API int initEvent(void (*sendEvent)(const char*, void*));
WINMMJOY_API void cleanup();
} }

View File

@ -21,6 +21,8 @@
#include "synergy/IClient.h" #include "synergy/IClient.h"
#include "base/String.h" #include "base/String.h"
namespace synergy { class IStream; }
//! Generic proxy for client or primary //! Generic proxy for client or primary
class BaseClientProxy : public IClient { class BaseClientProxy : public IClient {
public: public:
@ -82,6 +84,8 @@ public:
size_t size) = 0; size_t size) = 0;
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0;
virtual String getName() const; virtual String getName() const;
virtual synergy::IStream*
getStream() const = 0;
private: private:
String m_name; String m_name;

View File

@ -27,7 +27,6 @@
#include "net/XSocket.h" #include "net/XSocket.h"
#include "io/CryptoStream.h" #include "io/CryptoStream.h"
#include "io/CryptoOptions.h" #include "io/CryptoOptions.h"
#include "io/IStreamFilterFactory.h"
#include "base/Log.h" #include "base/Log.h"
#include "base/IEventQueue.h" #include "base/IEventQueue.h"
#include "base/TMethodEventJob.h" #include "base/TMethodEventJob.h"
@ -36,13 +35,17 @@
// ClientListener // ClientListener
// //
#if defined _WIN32
static const char s_networkSecurity[] = { "ns" };
#else
static const char s_networkSecurity[] = { "libns" };
#endif
ClientListener::ClientListener(const NetworkAddress& address, ClientListener::ClientListener(const NetworkAddress& address,
ISocketFactory* socketFactory, ISocketFactory* socketFactory,
IStreamFilterFactory* streamFilterFactory,
const CryptoOptions& crypto, const CryptoOptions& crypto,
IEventQueue* events) : IEventQueue* events) :
m_socketFactory(socketFactory), m_socketFactory(socketFactory),
m_streamFilterFactory(streamFilterFactory),
m_server(NULL), m_server(NULL),
m_crypto(crypto), m_crypto(crypto),
m_events(events) m_events(events)
@ -51,22 +54,21 @@ ClientListener::ClientListener(const NetworkAddress& address,
try { try {
// create listen socket // create listen socket
m_listen = m_socketFactory->createListen(); m_useSecureNetwork = ARCH->plugin().exists(s_networkSecurity);
m_listen = m_socketFactory->createListen(m_useSecureNetwork);
// bind listen address // bind listen address
LOG((CLOG_DEBUG1 "binding listen socket")); LOG((CLOG_DEBUG1 "binding listen socket"));
m_listen->bind(address); m_listen->bind(address);
} }
catch (XSocketAddressInUse&) { catch (XSocketAddressInUse&) {
delete m_listen; cleanupListenSocket();
delete m_socketFactory; delete m_socketFactory;
delete m_streamFilterFactory;
throw; throw;
} }
catch (XBase&) { catch (XBase&) {
delete m_listen; cleanupListenSocket();
delete m_socketFactory; delete m_socketFactory;
delete m_streamFilterFactory;
throw; throw;
} }
LOG((CLOG_DEBUG1 "listening for clients")); LOG((CLOG_DEBUG1 "listening for clients"));
@ -102,9 +104,8 @@ ClientListener::~ClientListener()
} }
m_events->removeHandler(m_events->forIListenSocket().connecting(), m_listen); m_events->removeHandler(m_events->forIListenSocket().connecting(), m_listen);
delete m_listen; cleanupListenSocket();
delete m_socketFactory; delete m_socketFactory;
delete m_streamFilterFactory;
} }
void void
@ -114,6 +115,12 @@ ClientListener::setServer(Server* server)
m_server = server; m_server = server;
} }
void
ClientListener::deleteSocket(void* socket)
{
m_listen->deleteSocket(socket);
}
ClientProxy* ClientProxy*
ClientListener::getNextClient() ClientListener::getNextClient()
{ {
@ -130,17 +137,18 @@ void
ClientListener::handleClientConnecting(const Event&, void*) ClientListener::handleClientConnecting(const Event&, void*)
{ {
// accept client connection // accept client connection
synergy::IStream* stream = m_listen->accept(); IDataSocket* socket = m_listen->accept();
synergy::IStream* stream = socket;
if (stream == NULL) { if (stream == NULL) {
return; return;
} }
LOG((CLOG_NOTE "accepted client connection")); LOG((CLOG_NOTE "accepted client connection"));
// filter socket messages, including a packetizing filter // filter socket messages, including a packetizing filter
if (m_streamFilterFactory != NULL) { bool adopt = !m_useSecureNetwork;
stream = m_streamFilterFactory->create(stream, true); stream = new PacketStreamFilter(m_events, stream, adopt);
}
stream = new PacketStreamFilter(m_events, stream, true);
if (m_crypto.m_mode != kDisabled) { if (m_crypto.m_mode != kDisabled) {
CryptoStream* cryptoStream = new CryptoStream( CryptoStream* cryptoStream = new CryptoStream(
@ -150,6 +158,12 @@ ClientListener::handleClientConnecting(const Event&, void*)
assert(m_server != NULL); assert(m_server != NULL);
if (m_useSecureNetwork) {
while(!socket->isReady()) {
ARCH->sleep(.5f);
}
}
// create proxy for unknown client // create proxy for unknown client
ClientProxyUnknown* client = new ClientProxyUnknown(stream, 30.0, m_server, m_events); ClientProxyUnknown* client = new ClientProxyUnknown(stream, 30.0, m_server, m_events);
m_newClients.insert(client); m_newClients.insert(client);
@ -174,6 +188,7 @@ ClientListener::handleUnknownClient(const Event&, void* vclient)
// get the real client proxy and install it // get the real client proxy and install it
ClientProxy* client = unknownClient->orphanClientProxy(); ClientProxy* client = unknownClient->orphanClientProxy();
bool handshakeOk = true;
if (client != NULL) { if (client != NULL) {
// handshake was successful // handshake was successful
m_waitingClients.push_back(client); m_waitingClients.push_back(client);
@ -185,12 +200,25 @@ ClientListener::handleUnknownClient(const Event&, void* vclient)
&ClientListener::handleClientDisconnected, &ClientListener::handleClientDisconnected,
client)); client));
} }
else {
handshakeOk = false;
}
// now finished with unknown client // now finished with unknown client
m_events->removeHandler(m_events->forClientProxyUnknown().success(), client); m_events->removeHandler(m_events->forClientProxyUnknown().success(), client);
m_events->removeHandler(m_events->forClientProxyUnknown().failure(), client); m_events->removeHandler(m_events->forClientProxyUnknown().failure(), client);
m_newClients.erase(unknownClient); m_newClients.erase(unknownClient);
PacketStreamFilter* streamFileter = dynamic_cast<PacketStreamFilter*>(unknownClient->getStream());
IDataSocket* socket = NULL;
if (streamFileter != NULL) {
socket = dynamic_cast<IDataSocket*>(streamFileter->getStream());
}
delete unknownClient; delete unknownClient;
if (m_useSecureNetwork && !handshakeOk) {
deleteSocket(socket);
}
} }
void void
@ -210,3 +238,17 @@ ClientListener::handleClientDisconnected(const Event&, void* vclient)
} }
} }
} }
void
ClientListener::cleanupListenSocket()
{
if (!m_useSecureNetwork) {
delete m_listen;
}
else {
ARCH->plugin().invoke(
s_networkSecurity,
"deleteListenSocket",
NULL);
}
}

View File

@ -30,7 +30,6 @@ class ClientProxyUnknown;
class NetworkAddress; class NetworkAddress;
class IListenSocket; class IListenSocket;
class ISocketFactory; class ISocketFactory;
class IStreamFilterFactory;
class Server; class Server;
class IEventQueue; class IEventQueue;
@ -39,7 +38,6 @@ public:
// The factories are adopted. // The factories are adopted.
ClientListener(const NetworkAddress&, ClientListener(const NetworkAddress&,
ISocketFactory*, ISocketFactory*,
IStreamFilterFactory*,
const CryptoOptions& crypto, const CryptoOptions& crypto,
IEventQueue* events); IEventQueue* events);
~ClientListener(); ~ClientListener();
@ -51,6 +49,8 @@ public:
//@} //@}
void deleteSocket(void* socket);
//! @name accessors //! @name accessors
//@{ //@{
@ -73,16 +73,18 @@ private:
void handleUnknownClient(const Event&, void*); void handleUnknownClient(const Event&, void*);
void handleClientDisconnected(const Event&, void*); void handleClientDisconnected(const Event&, void*);
void cleanupListenSocket();
private: private:
typedef std::set<ClientProxyUnknown*> NewClients; typedef std::set<ClientProxyUnknown*> NewClients;
typedef std::deque<ClientProxy*> WaitingClients; typedef std::deque<ClientProxy*> WaitingClients;
IListenSocket* m_listen; IListenSocket* m_listen;
ISocketFactory* m_socketFactory; ISocketFactory* m_socketFactory;
IStreamFilterFactory* m_streamFilterFactory;
NewClients m_newClients; NewClients m_newClients;
WaitingClients m_waitingClients; WaitingClients m_waitingClients;
Server* m_server; Server* m_server;
CryptoOptions m_crypto; CryptoOptions m_crypto;
IEventQueue* m_events; IEventQueue* m_events;
bool m_useSecureNetwork;
}; };

View File

@ -43,6 +43,9 @@ public:
*/ */
ClientProxy* orphanClientProxy(); ClientProxy* orphanClientProxy();
//! Get the stream
synergy::IStream* getStream() { return m_stream; }
//@} //@}
private: private:

View File

@ -146,6 +146,9 @@ public:
virtual void sendDragInfo(UInt32 fileCount, const char* info, size_t size); virtual void sendDragInfo(UInt32 fileCount, const char* info, size_t size);
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
virtual synergy::IStream*
getStream() const { return NULL; }
private: private:
synergy::Screen* m_screen; synergy::Screen* m_screen;
bool m_clipboardDirty[kClipboardEnd]; bool m_clipboardDirty[kClipboardEnd];

View File

@ -21,6 +21,7 @@
#include "server/ClientProxy.h" #include "server/ClientProxy.h"
#include "server/ClientProxyUnknown.h" #include "server/ClientProxyUnknown.h"
#include "server/PrimaryClient.h" #include "server/PrimaryClient.h"
#include "server/ClientListener.h"
#include "synergy/IPlatformScreen.h" #include "synergy/IPlatformScreen.h"
#include "synergy/DropHelper.h" #include "synergy/DropHelper.h"
#include "synergy/option_types.h" #include "synergy/option_types.h"
@ -30,6 +31,8 @@
#include "synergy/FileChunker.h" #include "synergy/FileChunker.h"
#include "synergy/KeyState.h" #include "synergy/KeyState.h"
#include "synergy/Screen.h" #include "synergy/Screen.h"
#include "synergy/PacketStreamFilter.h"
#include "net/TCPSocket.h"
#include "net/IDataSocket.h" #include "net/IDataSocket.h"
#include "net/IListenSocket.h" #include "net/IListenSocket.h"
#include "net/XSocket.h" #include "net/XSocket.h"
@ -1358,7 +1361,11 @@ Server::handleClientDisconnected(const Event&, void* vclient)
BaseClientProxy* client = reinterpret_cast<BaseClientProxy*>(vclient); BaseClientProxy* client = reinterpret_cast<BaseClientProxy*>(vclient);
removeActiveClient(client); removeActiveClient(client);
removeOldClient(client); removeOldClient(client);
PacketStreamFilter* streamFileter = dynamic_cast<PacketStreamFilter*>(client->getStream());
TCPSocket* socket = dynamic_cast<TCPSocket*>(streamFileter->getStream());
delete client; delete client;
m_clientListener->deleteSocket(socket);
} }
void void
@ -1368,7 +1375,10 @@ Server::handleClientCloseTimeout(const Event&, void* vclient)
BaseClientProxy* client = reinterpret_cast<BaseClientProxy*>(vclient); BaseClientProxy* client = reinterpret_cast<BaseClientProxy*>(vclient);
LOG((CLOG_NOTE "forced disconnection of client \"%s\"", getName(client).c_str())); LOG((CLOG_NOTE "forced disconnection of client \"%s\"", getName(client).c_str()));
removeOldClient(client); removeOldClient(client);
PacketStreamFilter* streamFileter = dynamic_cast<PacketStreamFilter*>(client->getStream());
TCPSocket* socket = dynamic_cast<TCPSocket*>(streamFileter->getStream());
delete client; delete client;
m_clientListener->deleteSocket(socket);
} }
void void

View File

@ -39,6 +39,7 @@ class InputFilter;
namespace synergy { class Screen; } namespace synergy { class Screen; }
class IEventQueue; class IEventQueue;
class Thread; class Thread;
class ClientListener;
//! Synergy server //! Synergy server
/*! /*!
@ -155,6 +156,9 @@ public:
//! Received dragging information from client //! Received dragging information from client
void dragInfoReceived(UInt32 fileNum, String content); void dragInfoReceived(UInt32 fileNum, String content);
//! Store ClientListener pointer
void setListener(ClientListener* p) { m_clientListener = p; }
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -474,4 +478,6 @@ private:
Thread* m_getDragInfoThread; Thread* m_getDragInfoThread;
bool m_waitDragInfoThread; bool m_waitDragInfoThread;
ClientListener* m_clientListener;
}; };

View File

@ -326,7 +326,7 @@ ClientApp::handleClientDisconnected(const Event&, void*)
m_events->addEvent(Event(Event::kQuit)); m_events->addEvent(Event(Event::kQuit));
} }
else if (!m_suspended) { else if (!m_suspended) {
m_client->connect(); scheduleClientRestart(nextRestartTimeout());
} }
updateStatus(); updateStatus();
} }
@ -340,8 +340,7 @@ ClientApp::openClient(const String& name, const NetworkAddress& address,
m_events, m_events,
name, name,
address, address,
new CTCPSocketFactory(m_events, getSocketMultiplexer()), new TCPSocketFactory(m_events, getSocketMultiplexer()),
NULL,
screen, screen,
crypto, crypto,
args().m_enableDragDrop); args().m_enableDragDrop);
@ -458,6 +457,11 @@ ClientApp::mainLoop()
SocketMultiplexer multiplexer; SocketMultiplexer multiplexer;
setSocketMultiplexer(&multiplexer); setSocketMultiplexer(&multiplexer);
// load all available plugins.
ARCH->plugin().load();
// pass log and arch into plugins.
ARCH->plugin().init(Log::getInstance(), Arch::getInstance());
// start client, etc // start client, etc
appUtil().startNode(); appUtil().startNode();
@ -467,8 +471,8 @@ ClientApp::mainLoop()
initIpcClient(); initIpcClient();
} }
// load all available plugins. // init event for all available plugins.
ARCH->plugin().init(m_clientScreen->getEventTarget(), m_events); ARCH->plugin().initEvent(m_clientScreen->getEventTarget(), m_events);
// run event loop. if startClient() failed we're supposed to retry // run event loop. if startClient() failed we're supposed to retry
// later. the timer installed by startClient() will take care of // later. the timer installed by startClient() will take care of
@ -504,6 +508,9 @@ ClientApp::mainLoop()
cleanupIpcClient(); cleanupIpcClient();
} }
// unload all plugins.
ARCH->plugin().unload();
return kExitSuccess; return kExitSuccess;
} }

View File

@ -101,7 +101,7 @@ DragInformation::getDragFileExtension(String filename)
int int
DragInformation::setupDragInfo(DragFileList& fileList, String& output) DragInformation::setupDragInfo(DragFileList& fileList, String& output)
{ {
int size = fileList.size(); int size = static_cast<int>(fileList.size());
for (int i = 0; i < size; ++i) { for (int i = 0; i < size; ++i) {
output.append(fileList.at(i).getFilename()); output.append(fileList.at(i).getFilename());
output.append(","); output.append(",");

View File

@ -338,8 +338,8 @@ void
ServerApp::stopServer() ServerApp::stopServer()
{ {
if (m_serverState == kStarted) { if (m_serverState == kStarted) {
closeClientListener(m_listener);
closeServer(m_server); closeServer(m_server);
closeClientListener(m_listener);
m_server = NULL; m_server = NULL;
m_listener = NULL; m_listener = NULL;
m_serverState = kInitialized; m_serverState = kInitialized;
@ -543,6 +543,7 @@ ServerApp::startServer()
listener = openClientListener(args().m_config->getSynergyAddress()); listener = openClientListener(args().m_config->getSynergyAddress());
m_server = openServer(*args().m_config, m_primaryClient); m_server = openServer(*args().m_config, m_primaryClient);
listener->setServer(m_server); listener->setServer(m_server);
m_server->setListener(listener);
m_listener = listener; m_listener = listener;
updateStatus(); updateStatus();
LOG((CLOG_NOTE "started server, waiting for clients")); LOG((CLOG_NOTE "started server, waiting for clients"));
@ -631,8 +632,7 @@ ServerApp::openClientListener(const NetworkAddress& address)
{ {
ClientListener* listen = new ClientListener( ClientListener* listen = new ClientListener(
address, address,
new CTCPSocketFactory(m_events, getSocketMultiplexer()), new TCPSocketFactory(m_events, getSocketMultiplexer()),
NULL,
args().m_crypto, args().m_crypto,
m_events); m_events);
@ -707,6 +707,11 @@ ServerApp::mainLoop()
return kExitFailed; return kExitFailed;
} }
// load all available plugins.
ARCH->plugin().load();
// pass log and arch into plugins.
ARCH->plugin().init(Log::getInstance(), Arch::getInstance());
// start server, etc // start server, etc
appUtil().startNode(); appUtil().startNode();
@ -716,8 +721,8 @@ ServerApp::mainLoop()
initIpcClient(); initIpcClient();
} }
// load all available plugins. // init event for all available plugins.
ARCH->plugin().init(m_serverScreen->getEventTarget(), m_events); ARCH->plugin().initEvent(m_serverScreen->getEventTarget(), m_events);
// handle hangup signal by reloading the server's configuration // handle hangup signal by reloading the server's configuration
ARCH->setSignalHandler(Arch::kHANGUP, &reloadSignalHandler, NULL); ARCH->setSignalHandler(Arch::kHANGUP, &reloadSignalHandler, NULL);
@ -775,6 +780,9 @@ ServerApp::mainLoop()
cleanupIpcClient(); cleanupIpcClient();
} }
// unload all plugins.
ARCH->plugin().unload();
return kExitSuccess; return kExitSuccess;
} }

View File

@ -115,8 +115,8 @@ TEST_F(NetworkTests, sendToClient_mockData)
// server // server
SocketMultiplexer serverSocketMultiplexer; SocketMultiplexer serverSocketMultiplexer;
CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
ClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); ClientListener listener(serverAddress, serverSocketFactory, cryptoOptions, &m_events);
NiceMock<MockScreen> serverScreen; NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient; NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig; NiceMock<MockConfig> serverConfig;
@ -137,12 +137,12 @@ TEST_F(NetworkTests, sendToClient_mockData)
// client // client
NiceMock<MockScreen> clientScreen; NiceMock<MockScreen> clientScreen;
SocketMultiplexer clientSocketMultiplexer; SocketMultiplexer clientSocketMultiplexer;
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer); TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer);
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
Client client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions, true); Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, cryptoOptions, true);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveCompleted(), &client, m_events.forIScreen().fileRecieveCompleted(), &client,
@ -168,8 +168,8 @@ TEST_F(NetworkTests, sendToClient_mockFile)
// server // server
SocketMultiplexer serverSocketMultiplexer; SocketMultiplexer serverSocketMultiplexer;
CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
ClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); ClientListener listener(serverAddress, serverSocketFactory, cryptoOptions, &m_events);
NiceMock<MockScreen> serverScreen; NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient; NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig; NiceMock<MockConfig> serverConfig;
@ -190,12 +190,12 @@ TEST_F(NetworkTests, sendToClient_mockFile)
// client // client
NiceMock<MockScreen> clientScreen; NiceMock<MockScreen> clientScreen;
SocketMultiplexer clientSocketMultiplexer; SocketMultiplexer clientSocketMultiplexer;
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer); TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer);
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
Client client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions, true); Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, cryptoOptions, true);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveCompleted(), &client, m_events.forIScreen().fileRecieveCompleted(), &client,
@ -221,8 +221,8 @@ TEST_F(NetworkTests, sendToServer_mockData)
// server // server
SocketMultiplexer serverSocketMultiplexer; SocketMultiplexer serverSocketMultiplexer;
CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
ClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); ClientListener listener(serverAddress, serverSocketFactory, cryptoOptions, &m_events);
NiceMock<MockScreen> serverScreen; NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient; NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig; NiceMock<MockConfig> serverConfig;
@ -238,12 +238,12 @@ TEST_F(NetworkTests, sendToServer_mockData)
// client // client
NiceMock<MockScreen> clientScreen; NiceMock<MockScreen> clientScreen;
SocketMultiplexer clientSocketMultiplexer; SocketMultiplexer clientSocketMultiplexer;
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer); TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer);
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
Client client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions, true); Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, cryptoOptions, true);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forClientListener().connected(), &listener, m_events.forClientListener().connected(), &listener,
@ -274,8 +274,8 @@ TEST_F(NetworkTests, sendToServer_mockFile)
// server // server
SocketMultiplexer serverSocketMultiplexer; SocketMultiplexer serverSocketMultiplexer;
CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer);
ClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); ClientListener listener(serverAddress, serverSocketFactory, cryptoOptions, &m_events);
NiceMock<MockScreen> serverScreen; NiceMock<MockScreen> serverScreen;
NiceMock<MockPrimaryClient> primaryClient; NiceMock<MockPrimaryClient> primaryClient;
NiceMock<MockConfig> serverConfig; NiceMock<MockConfig> serverConfig;
@ -291,12 +291,12 @@ TEST_F(NetworkTests, sendToServer_mockFile)
// client // client
NiceMock<MockScreen> clientScreen; NiceMock<MockScreen> clientScreen;
SocketMultiplexer clientSocketMultiplexer; SocketMultiplexer clientSocketMultiplexer;
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer); TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer);
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
Client client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions, true); Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, cryptoOptions, true);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forClientListener().connected(), &listener, m_events.forClientListener().connected(), &listener,