diff --git a/.gitignore b/.gitignore index e400bc2f..4bdaf615 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ config.h /ext/cryptopp562 /ext/gmock-1.6.0 /ext/gtest-1.6.0 +/ext/openssl /src/gui/Makefile* /src/gui/object_script* /src/gui/tmp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6eb0190b..82c2f925 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,7 @@ if (UNIX) # warnings as errors: # 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. include(CheckIncludeFiles) @@ -174,7 +174,7 @@ if (UNIX) CACHE STRING "" FORCE) else() # >= 10.6: Intel only - set(CMAKE_OSX_ARCHITECTURES "i386;x86_64" + set(CMAKE_OSX_ARCHITECTURES "i386" CACHE STRING "" FORCE) endif() diff --git a/ext/openssl-1.0.1h.zip b/ext/openssl-1.0.1h.zip new file mode 100644 index 00000000..63796c0a Binary files /dev/null and b/ext/openssl-1.0.1h.zip differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0dec87f2..0adee82f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -16,7 +16,6 @@ add_subdirectory(lib) add_subdirectory(cmd) -add_subdirectory(plugin) add_subdirectory(micro) if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "IRIX") diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 6cbbcf45..2990d16d 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -23,9 +23,11 @@ add_subdirectory(ipc) add_subdirectory(mt) add_subdirectory(net) add_subdirectory(platform) +add_subdirectory(plugin) add_subdirectory(server) add_subdirectory(synergy) + if (WIN32) add_subdirectory(synwinhk) endif() diff --git a/src/lib/arch/Arch.cpp b/src/lib/arch/Arch.cpp index d06a873a..d76aca91 100644 --- a/src/lib/arch/Arch.cpp +++ b/src/lib/arch/Arch.cpp @@ -30,6 +30,11 @@ Arch::Arch() s_instance = this; } +Arch::Arch(Arch* arch) +{ + s_instance = arch; +} + Arch::~Arch() { #if SYSAPI_WIN32 diff --git a/src/lib/arch/Arch.h b/src/lib/arch/Arch.h index ad0719bf..bc624131 100644 --- a/src/lib/arch/Arch.h +++ b/src/lib/arch/Arch.h @@ -99,6 +99,7 @@ class Arch : public ARCH_CONSOLE, public ARCH_TIME { public: Arch(); + Arch(Arch* arch); virtual ~Arch(); //! Call init on other arch classes. diff --git a/src/lib/arch/CMakeLists.txt b/src/lib/arch/CMakeLists.txt index 131bec78..12946107 100644 --- a/src/lib/arch/CMakeLists.txt +++ b/src/lib/arch/CMakeLists.txt @@ -50,5 +50,5 @@ endif() add_library(arch STATIC ${sources}) if (UNIX) - target_link_libraries(arch ${libs}) + target_link_libraries(arch dl ${libs}) endif() diff --git a/src/lib/arch/IArchPlugin.h b/src/lib/arch/IArchPlugin.h index d45e7426..f6bfd599 100644 --- a/src/lib/arch/IArchPlugin.h +++ b/src/lib/arch/IArchPlugin.h @@ -21,6 +21,8 @@ #define PLUGINS_DIR "plugins" #include "common/IInterface.h" +#include "common/stdmap.h" +#include "base/String.h" class IEventQueue; @@ -34,11 +36,46 @@ public: //! @name manipulators //@{ - //! Load plugins + //!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 PluginTable; }; diff --git a/src/lib/arch/unix/ArchPluginUnix.cpp b/src/lib/arch/unix/ArchPluginUnix.cpp index 5cdacf3c..c4a87d41 100644 --- a/src/lib/arch/unix/ArchPluginUnix.cpp +++ b/src/lib/arch/unix/ArchPluginUnix.cpp @@ -18,6 +18,24 @@ #include "arch/unix/ArchPluginUnix.h" +#include "arch/unix/XArchUnix.h" +#include "base/IEventQueue.h" +#include "base/Event.h" +#include "base/Log.h" + +#include +#include +#include +#include + +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() { } @@ -27,6 +45,153 @@ ArchPluginUnix::~ArchPluginUnix() } 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 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::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)); +} + diff --git a/src/lib/arch/unix/ArchPluginUnix.h b/src/lib/arch/unix/ArchPluginUnix.h index f75274e4..092a1fd9 100644 --- a/src/lib/arch/unix/ArchPluginUnix.h +++ b/src/lib/arch/unix/ArchPluginUnix.h @@ -31,5 +31,21 @@ public: virtual ~ArchPluginUnix(); // 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); diff --git a/src/lib/arch/win32/ArchPluginWindows.cpp b/src/lib/arch/win32/ArchPluginWindows.cpp index d12445f8..45408ee1 100644 --- a/src/lib/arch/win32/ArchPluginWindows.cpp +++ b/src/lib/arch/win32/ArchPluginWindows.cpp @@ -27,7 +27,10 @@ #include #include -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; IEventQueue* g_events = NULL; @@ -41,11 +44,8 @@ ArchPluginWindows::~ArchPluginWindows() } void -ArchPluginWindows::init(void* eventTarget, IEventQueue* events) +ArchPluginWindows::load() { - g_eventTarget = eventTarget; - g_events = events; - String dir = getPluginsDir(); LOG((CLOG_DEBUG "plugins dir: %s", dir.c_str())); @@ -54,21 +54,113 @@ ArchPluginWindows::init(void* eventTarget, IEventQueue* events) getFilenames(pattern, plugins); std::vector::iterator it; - for (it = plugins.begin(); it != plugins.end(); ++it) - load(*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); + HINSTANCE library = LoadLibrary(path.c_str()); + + if (library == NULL) { + throw XArch(new XArchEvalWindows); + } + + void* lib = reinterpret_cast(library); + String filename = synergy::string::removeFileExt(*it); + m_pluginTable.insert(std::make_pair(filename, lib)); + } } void -ArchPluginWindows::load(const String& dllFilename) +ArchPluginWindows::unload() { - LOG((CLOG_DEBUG "loading plugin: %s", dllFilename.c_str())); - String path = String(getPluginsDir()).append("\\").append(dllFilename); - HINSTANCE library = LoadLibrary(path.c_str()); - if (library == NULL) - throw XArch(new XArchEvalWindows); + PluginTable::iterator it; + HINSTANCE lib; + for (it = m_pluginTable.begin(); it != m_pluginTable.end(); it++) { + lib = reinterpret_cast(it->second); + 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"); - initPlugin(&sendEvent, &log); + LOG((CLOG_DEBUG "unloading plugin: %s", it->first.c_str())); + 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(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(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(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 diff --git a/src/lib/arch/win32/ArchPluginWindows.h b/src/lib/arch/win32/ArchPluginWindows.h index a49178c0..fdde9169 100644 --- a/src/lib/arch/win32/ArchPluginWindows.h +++ b/src/lib/arch/win32/ArchPluginWindows.h @@ -19,7 +19,6 @@ #pragma once #include "arch/IArchPlugin.h" -#include "base/String.h" #include @@ -35,13 +34,22 @@ public: virtual ~ArchPluginWindows(); // 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: String getModuleDir(); void getFilenames(const String& pattern, std::vector& filenames); - void load(const String& dllPath); String getPluginsDir(); + +private: + PluginTable m_pluginTable; }; void sendEvent(const char* text, void* data); diff --git a/src/lib/base/Log.cpp b/src/lib/base/Log.cpp index 2ea91ffb..7017d972 100644 --- a/src/lib/base/Log.cpp +++ b/src/lib/base/Log.cpp @@ -74,6 +74,11 @@ Log::Log() s_log = this; } +Log::Log(Log* src) +{ + s_log = src; +} + Log::~Log() { // clean up diff --git a/src/lib/base/Log.h b/src/lib/base/Log.h index 3c8974ad..fd5273b9 100644 --- a/src/lib/base/Log.h +++ b/src/lib/base/Log.h @@ -41,6 +41,7 @@ LOGC() provide convenient access. class Log { public: Log(); + Log(Log* src); ~Log(); //! @name manipulators diff --git a/src/lib/base/String.cpp b/src/lib/base/String.cpp index 590b660a..4ce38899 100644 --- a/src/lib/base/String.cpp +++ b/src/lib/base/String.cpp @@ -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 diff --git a/src/lib/base/String.h b/src/lib/base/String.h index e0e3b7c6..9d137143 100644 --- a/src/lib/base/String.h +++ b/src/lib/base/String.h @@ -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); +//! Remove file extension +/*! +Finds the last dot and remove all characters from the dot to the end +*/ +String removeFileExt(String filename); + //! Case-insensitive comparisons /*! This class provides case-insensitve comparison functions. diff --git a/src/lib/client/Client.cpp b/src/lib/client/Client.cpp index 4620116d..8b7d5b69 100644 --- a/src/lib/client/Client.cpp +++ b/src/lib/client/Client.cpp @@ -18,6 +18,7 @@ #include "client/Client.h" +#include "../plugin/ns/SecureSocket.h" #include "client/ServerProxy.h" #include "synergy/Screen.h" #include "synergy/Clipboard.h" @@ -29,8 +30,8 @@ #include "synergy/FileChunker.h" #include "synergy/IPlatformScreen.h" #include "mt/Thread.h" -#include "io/IStreamFilterFactory.h" #include "io/CryptoStream.h" +#include "net/TCPSocket.h" #include "net/IDataSocket.h" #include "net/ISocketFactory.h" #include "arch/Arch.h" @@ -45,6 +46,12 @@ #include #include +#if defined _WIN32 +static const char s_networkSecurity[] = { "ns" }; +#else +static const char s_networkSecurity[] = { "libns" }; +#endif + // // Client // @@ -53,7 +60,6 @@ Client::Client( IEventQueue* events, const String& name, const NetworkAddress& address, ISocketFactory* socketFactory, - IStreamFilterFactory* streamFilterFactory, synergy::Screen* screen, const CryptoOptions& crypto, bool enableDragDrop) : @@ -61,7 +67,6 @@ Client::Client( m_name(name), m_serverAddress(address), m_socketFactory(socketFactory), - m_streamFilterFactory(streamFilterFactory), m_screen(screen), m_stream(NULL), m_timer(NULL), @@ -75,7 +80,9 @@ Client::Client( m_crypto(crypto), m_sendFileThread(NULL), m_writeToDropDirThread(NULL), - m_enableDragDrop(enableDragDrop) + m_enableDragDrop(enableDragDrop), + m_socket(NULL), + m_useSecureNetwork(false) { assert(m_socketFactory != NULL); assert(m_screen != NULL); @@ -118,7 +125,6 @@ Client::~Client() cleanupConnecting(); cleanupConnection(); delete m_socketFactory; - delete m_streamFilterFactory; } void @@ -150,14 +156,14 @@ Client::connect() } // 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(socket); // filter socket messages, including a packetizing filter m_stream = socket; - if (m_streamFilterFactory != NULL) { - m_stream = m_streamFilterFactory->create(m_stream, true); - } - m_stream = new PacketStreamFilter(m_events, m_stream, true); + bool adopt = !m_useSecureNetwork; + m_stream = new PacketStreamFilter(m_events, m_stream, adopt); if (m_crypto.m_mode != kDisabled) { m_cryptoStream = new CryptoStream( @@ -174,8 +180,7 @@ Client::connect() catch (XBase& e) { cleanupTimer(); cleanupConnecting(); - delete m_stream; - m_stream = NULL; + cleanupStream(); LOG((CLOG_DEBUG1 "connection failed")); sendConnectionFailedEvent(e.what()); return; @@ -532,8 +537,7 @@ Client::cleanupConnection() m_stream->getEventTarget()); m_events->removeHandler(m_events->forISocket().disconnected(), m_stream->getEventTarget()); - delete m_stream; - m_stream = NULL; + cleanupStream(); } } @@ -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 Client::handleConnected(const Event&, void*) { @@ -577,6 +595,8 @@ Client::handleConnected(const Event&, void*) m_sentClipboard[id] = false; m_timeClipboard[id] = 0; } + + m_socket->secureConnect(); } void @@ -587,8 +607,7 @@ Client::handleConnectionFailed(const Event& event, void*) cleanupTimer(); cleanupConnecting(); - delete m_stream; - m_stream = NULL; + cleanupStream(); LOG((CLOG_DEBUG1 "connection failed")); sendConnectionFailedEvent(info->m_what.c_str()); delete info; @@ -600,8 +619,7 @@ Client::handleConnectTimeout(const Event&, void*) cleanupTimer(); cleanupConnecting(); cleanupConnection(); - delete m_stream; - m_stream = NULL; + cleanupStream(); LOG((CLOG_DEBUG1 "connection timed out")); sendConnectionFailedEvent("Timed out"); } diff --git a/src/lib/client/Client.h b/src/lib/client/Client.h index 144d007d..be32999f 100644 --- a/src/lib/client/Client.h +++ b/src/lib/client/Client.h @@ -33,10 +33,10 @@ class ServerProxy; class IDataSocket; class ISocketFactory; namespace synergy { class IStream; } -class IStreamFilterFactory; class IEventQueue; class CryptoStream; class Thread; +class TCPSocket; //! Synergy client /*! @@ -60,7 +60,6 @@ public: Client(IEventQueue* events, const String& name, const NetworkAddress& address, ISocketFactory* socketFactory, - IStreamFilterFactory* streamFilterFactory, synergy::Screen* screen, const CryptoOptions& crypto, bool enableDragDrop); @@ -189,6 +188,7 @@ private: void cleanupConnection(); void cleanupScreen(); void cleanupTimer(); + void cleanupStream(); void handleConnected(const Event&, void*); void handleConnectionFailed(const Event&, void*); void handleConnectTimeout(const Event&, void*); @@ -204,33 +204,34 @@ private: void onFileRecieveCompleted(); public: - bool m_mock; + bool m_mock; private: - String m_name; - NetworkAddress m_serverAddress; - ISocketFactory* m_socketFactory; - IStreamFilterFactory* m_streamFilterFactory; - synergy::Screen* m_screen; - synergy::IStream* m_stream; - EventQueueTimer* m_timer; - ServerProxy* m_server; - bool m_ready; - bool m_active; - bool m_suspended; - bool m_connectOnResume; - bool m_ownClipboard[kClipboardEnd]; - bool m_sentClipboard[kClipboardEnd]; - IClipboard::Time m_timeClipboard[kClipboardEnd]; - String m_dataClipboard[kClipboardEnd]; - IEventQueue* m_events; - CryptoStream* m_cryptoStream; - CryptoOptions m_crypto; - std::size_t m_expectedFileSize; - String m_receivedFileData; - DragFileList m_dragFileList; - String m_dragFileExt; + String m_name; + NetworkAddress m_serverAddress; + ISocketFactory* m_socketFactory; + synergy::Screen* m_screen; + synergy::IStream* m_stream; + EventQueueTimer* m_timer; + ServerProxy* m_server; + bool m_ready; + bool m_active; + bool m_suspended; + bool m_connectOnResume; + bool m_ownClipboard[kClipboardEnd]; + bool m_sentClipboard[kClipboardEnd]; + IClipboard::Time m_timeClipboard[kClipboardEnd]; + String m_dataClipboard[kClipboardEnd]; + IEventQueue* m_events; + CryptoStream* m_cryptoStream; + CryptoOptions m_crypto; + std::size_t m_expectedFileSize; + String m_receivedFileData; + DragFileList m_dragFileList; + String m_dragFileExt; Thread* m_sendFileThread; Thread* m_writeToDropDirThread; - bool m_enableDragDrop; + bool m_enableDragDrop; + TCPSocket* m_socket; + bool m_useSecureNetwork; }; diff --git a/src/lib/io/StreamFilter.h b/src/lib/io/StreamFilter.h index 84a4cf54..f9986801 100644 --- a/src/lib/io/StreamFilter.h +++ b/src/lib/io/StreamFilter.h @@ -49,13 +49,13 @@ public: virtual bool isReady() const; virtual UInt32 getSize() const; -protected: //! Get the stream /*! Returns the stream passed to the c'tor. */ synergy::IStream* getStream() const; +protected: //! Handle events from source stream /*! Does the event filtering. The default simply dispatches an event diff --git a/src/lib/ipc/IpcClient.h b/src/lib/ipc/IpcClient.h index d990a35e..f9b1c9ab 100644 --- a/src/lib/ipc/IpcClient.h +++ b/src/lib/ipc/IpcClient.h @@ -58,7 +58,7 @@ private: private: NetworkAddress m_serverAddress; - CTCPSocket m_socket; + TCPSocket m_socket; IpcServerProxy* m_server; IEventQueue* m_events; }; diff --git a/src/lib/mt/Thread.cpp b/src/lib/mt/Thread.cpp index 2ca7554f..dd45d872 100644 --- a/src/lib/mt/Thread.cpp +++ b/src/lib/mt/Thread.cpp @@ -18,6 +18,7 @@ #include "mt/Thread.h" +#include "net/XSocket.h" #include "mt/XMT.h" #include "mt/XThread.h" #include "arch/Arch.h" @@ -158,6 +159,10 @@ Thread::threadFunc(void* vjob) LOG((CLOG_DEBUG1 "thread 0x%08x exit", id)); } + catch (XSocket& e) { + // client called cancel() + LOG((CLOG_DEBUG "%s", e.what())); + } catch (XThreadCancel&) { // client called cancel() LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id)); diff --git a/src/lib/net/IListenSocket.h b/src/lib/net/IListenSocket.h index ab4fdeff..e6c98833 100644 --- a/src/lib/net/IListenSocket.h +++ b/src/lib/net/IListenSocket.h @@ -39,7 +39,15 @@ public: data stream. Returns NULL if no socket is waiting to be accepted. 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; //@} diff --git a/src/lib/net/ISocketFactory.h b/src/lib/net/ISocketFactory.h index aca45d54..5c86a0bc 100644 --- a/src/lib/net/ISocketFactory.h +++ b/src/lib/net/ISocketFactory.h @@ -34,10 +34,10 @@ public: //@{ //! Create data socket - virtual IDataSocket* create() const = 0; + virtual IDataSocket* create(bool secure) const = 0; //! Create listen socket - virtual IListenSocket* createListen() const = 0; + virtual IListenSocket* createListen(bool secure) const = 0; //@} }; diff --git a/src/lib/net/SocketMultiplexer.h b/src/lib/net/SocketMultiplexer.h index df49fb6d..c450aaea 100644 --- a/src/lib/net/SocketMultiplexer.h +++ b/src/lib/net/SocketMultiplexer.h @@ -96,15 +96,16 @@ private: private: Mutex* m_mutex; - Thread* m_thread; + Thread* m_thread; bool m_update; CondVar* m_jobsReady; CondVar* m_jobListLock; CondVar* m_jobListLockLocked; - Thread* m_jobListLocker; - Thread* m_jobListLockLocker; + Thread* m_jobListLocker; + Thread* m_jobListLockLocker; SocketJobs m_socketJobs; SocketJobMap m_socketJobMap; - ISocketMultiplexerJob* m_cursorMark; + ISocketMultiplexerJob* + m_cursorMark; }; diff --git a/src/lib/net/TCPListenSocket.cpp b/src/lib/net/TCPListenSocket.cpp index bf6fa91a..cdbd73c4 100644 --- a/src/lib/net/TCPListenSocket.cpp +++ b/src/lib/net/TCPListenSocket.cpp @@ -110,7 +110,7 @@ TCPListenSocket::accept() { IDataSocket* socket = NULL; 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) { m_socketMultiplexer->addSocket(this, new TSocketMultiplexerMethodJob( diff --git a/src/lib/net/TCPListenSocket.h b/src/lib/net/TCPListenSocket.h index bb9ae310..ef2687db 100644 --- a/src/lib/net/TCPListenSocket.h +++ b/src/lib/net/TCPListenSocket.h @@ -33,7 +33,7 @@ A listen socket using TCP. class TCPListenSocket : public IListenSocket { public: TCPListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer); - ~TCPListenSocket(); + virtual ~TCPListenSocket(); // ISocket overrides virtual void bind(const NetworkAddress&); @@ -41,16 +41,18 @@ public: virtual void* getEventTarget() const; // IListenSocket overrides - virtual IDataSocket* accept(); + virtual IDataSocket* + accept(); + virtual void deleteSocket(void*) { } -private: +public: ISocketMultiplexerJob* serviceListening(ISocketMultiplexerJob*, bool, bool, bool); -private: +protected: ArchSocket m_socket; Mutex* m_mutex; IEventQueue* m_events; - SocketMultiplexer* m_socketMultiplexer; + SocketMultiplexer* m_socketMultiplexer; }; diff --git a/src/lib/net/TCPSocket.cpp b/src/lib/net/TCPSocket.cpp index ad8d5510..c54df40b 100644 --- a/src/lib/net/TCPSocket.cpp +++ b/src/lib/net/TCPSocket.cpp @@ -34,10 +34,10 @@ #include // -// CTCPSocket +// TCPSocket // -CTCPSocket::CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : +TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : IDataSocket(events), m_mutex(), m_flushed(&m_mutex, true), @@ -54,7 +54,7 @@ CTCPSocket::CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer init(); } -CTCPSocket::CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket) : +TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket) : IDataSocket(events), m_mutex(), m_socket(socket), @@ -70,7 +70,7 @@ CTCPSocket::CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer setJob(newJob()); } -CTCPSocket::~CTCPSocket() +TCPSocket::~TCPSocket() { try { close(); @@ -81,7 +81,7 @@ CTCPSocket::~CTCPSocket() } void -CTCPSocket::bind(const NetworkAddress& addr) +TCPSocket::bind(const NetworkAddress& addr) { try { ARCH->bindSocket(m_socket, addr.getAddress()); @@ -95,7 +95,7 @@ CTCPSocket::bind(const NetworkAddress& addr) } void -CTCPSocket::close() +TCPSocket::close() { // remove ourself from the multiplexer setJob(NULL); @@ -123,13 +123,13 @@ CTCPSocket::close() } void* -CTCPSocket::getEventTarget() const +TCPSocket::getEventTarget() const { return const_cast(reinterpret_cast(this)); } UInt32 -CTCPSocket::read(void* buffer, UInt32 n) +TCPSocket::read(void* buffer, UInt32 n) { // copy data directly from our input buffer Lock lock(&m_mutex); @@ -152,7 +152,7 @@ CTCPSocket::read(void* buffer, UInt32 n) } void -CTCPSocket::write(const void* buffer, UInt32 n) +TCPSocket::write(const void* buffer, UInt32 n) { bool wasEmpty; { @@ -184,7 +184,7 @@ CTCPSocket::write(const void* buffer, UInt32 n) } void -CTCPSocket::flush() +TCPSocket::flush() { Lock lock(&m_mutex); while (m_flushed == false) { @@ -193,7 +193,7 @@ CTCPSocket::flush() } void -CTCPSocket::shutdownInput() +TCPSocket::shutdownInput() { bool useNewJob = false; { @@ -220,7 +220,7 @@ CTCPSocket::shutdownInput() } void -CTCPSocket::shutdownOutput() +TCPSocket::shutdownOutput() { bool useNewJob = false; { @@ -247,21 +247,21 @@ CTCPSocket::shutdownOutput() } bool -CTCPSocket::isReady() const +TCPSocket::isReady() const { Lock lock(&m_mutex); return (m_inputBuffer.getSize() > 0); } UInt32 -CTCPSocket::getSize() const +TCPSocket::getSize() const { Lock lock(&m_mutex); return m_inputBuffer.getSize(); } void -CTCPSocket::connect(const NetworkAddress& addr) +TCPSocket::connect(const NetworkAddress& addr) { { Lock lock(&m_mutex); @@ -290,7 +290,7 @@ CTCPSocket::connect(const NetworkAddress& addr) } void -CTCPSocket::init() +TCPSocket::init() { // default state m_connected = false; @@ -316,7 +316,7 @@ CTCPSocket::init() } void -CTCPSocket::setJob(ISocketMultiplexerJob* job) +TCPSocket::setJob(ISocketMultiplexerJob* job) { // multiplexer will delete the old job if (job == NULL) { @@ -328,7 +328,7 @@ CTCPSocket::setJob(ISocketMultiplexerJob* job) } ISocketMultiplexerJob* -CTCPSocket::newJob() +TCPSocket::newJob() { // note -- must have m_mutex locked on entry @@ -340,23 +340,23 @@ CTCPSocket::newJob() if (!(m_readable || m_writable)) { return NULL; } - return new TSocketMultiplexerMethodJob( - this, &CTCPSocket::serviceConnecting, + return new TSocketMultiplexerMethodJob( + this, &TCPSocket::serviceConnecting, m_socket, m_readable, m_writable); } else { if (!(m_readable || (m_writable && (m_outputBuffer.getSize() > 0)))) { return NULL; } - return new TSocketMultiplexerMethodJob( - this, &CTCPSocket::serviceConnected, + return new TSocketMultiplexerMethodJob( + this, &TCPSocket::serviceConnected, m_socket, m_readable, m_writable && (m_outputBuffer.getSize() > 0)); } } void -CTCPSocket::sendConnectionFailedEvent(const char* msg) +TCPSocket::sendConnectionFailedEvent(const char* msg) { ConnectionFailedInfo* info = new ConnectionFailedInfo(msg); m_events->addEvent(Event(m_events->forIDataSocket().connectionFailed(), @@ -364,13 +364,13 @@ CTCPSocket::sendConnectionFailedEvent(const char* msg) } void -CTCPSocket::sendEvent(Event::Type type) +TCPSocket::sendEvent(Event::Type type) { m_events->addEvent(Event(type, getEventTarget(), NULL)); } void -CTCPSocket::onConnected() +TCPSocket::onConnected() { m_connected = true; m_readable = true; @@ -378,14 +378,14 @@ CTCPSocket::onConnected() } void -CTCPSocket::onInputShutdown() +TCPSocket::onInputShutdown() { m_inputBuffer.pop(m_inputBuffer.getSize()); m_readable = false; } void -CTCPSocket::onOutputShutdown() +TCPSocket::onOutputShutdown() { m_outputBuffer.pop(m_outputBuffer.getSize()); m_writable = false; @@ -396,7 +396,7 @@ CTCPSocket::onOutputShutdown() } void -CTCPSocket::onDisconnected() +TCPSocket::onDisconnected() { // disconnected onInputShutdown(); @@ -405,7 +405,7 @@ CTCPSocket::onDisconnected() } ISocketMultiplexerJob* -CTCPSocket::serviceConnecting(ISocketMultiplexerJob* job, +TCPSocket::serviceConnecting(ISocketMultiplexerJob* job, bool, bool write, bool error) { Lock lock(&m_mutex); @@ -449,7 +449,7 @@ CTCPSocket::serviceConnecting(ISocketMultiplexerJob* job, } ISocketMultiplexerJob* -CTCPSocket::serviceConnected(ISocketMultiplexerJob* job, +TCPSocket::serviceConnected(ISocketMultiplexerJob* job, bool read, bool write, bool error) { Lock lock(&m_mutex); @@ -467,7 +467,17 @@ CTCPSocket::serviceConnected(ISocketMultiplexerJob* job, // write data UInt32 n = m_outputBuffer.getSize(); const void* buffer = m_outputBuffer.peek(n); - n = (UInt32)ARCH->writeSocket(m_socket, buffer, n); + if (isSecure()) { + if (isSecureReady()) { + n = secureWrite(buffer, n); + } + else { + return job; + } + } + else { + n = (UInt32)ARCH->writeSocket(m_socket, buffer, n); + } // discard written data if (n > 0) { @@ -510,14 +520,34 @@ CTCPSocket::serviceConnected(ISocketMultiplexerJob* job, if (read && m_readable) { try { 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) { bool wasEmpty = (m_inputBuffer.getSize() == 0); // slurp up as much as possible do { m_inputBuffer.write(buffer, (UInt32)n); - n = ARCH->readSocket(m_socket, buffer, sizeof(buffer)); + + if (isSecure() && isSecureReady()) { + n = secureRead(buffer, sizeof(buffer)); + } + else { + n = ARCH->readSocket(m_socket, buffer, sizeof(buffer)); + } + } while (n > 0); // send input ready if input buffer was empty diff --git a/src/lib/net/TCPSocket.h b/src/lib/net/TCPSocket.h index 0983a360..832cd128 100644 --- a/src/lib/net/TCPSocket.h +++ b/src/lib/net/TCPSocket.h @@ -34,11 +34,11 @@ class SocketMultiplexer; /*! A data socket using TCP. */ -class CTCPSocket : public IDataSocket { +class TCPSocket : public IDataSocket { public: - CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer); - CTCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket); - ~CTCPSocket(); + TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer); + TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket); + virtual ~TCPSocket(); // ISocket overrides virtual void bind(const NetworkAddress&); @@ -57,14 +57,31 @@ public: // IDataSocket overrides 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: void init(); - void setJob(ISocketMultiplexerJob*); - ISocketMultiplexerJob* newJob(); void sendConnectionFailedEvent(const char*); - void sendEvent(Event::Type); - void onConnected(); void onInputShutdown(); void onOutputShutdown(); @@ -87,5 +104,5 @@ private: bool m_readable; bool m_writable; IEventQueue* m_events; - SocketMultiplexer* m_socketMultiplexer; + SocketMultiplexer* m_socketMultiplexer; }; diff --git a/src/lib/net/TCPSocketFactory.cpp b/src/lib/net/TCPSocketFactory.cpp index c7755957..b17eac5a 100644 --- a/src/lib/net/TCPSocketFactory.cpp +++ b/src/lib/net/TCPSocketFactory.cpp @@ -20,31 +20,65 @@ #include "net/TCPSocket.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_socketMultiplexer(socketMultiplexer) { // do nothing } -CTCPSocketFactory::~CTCPSocketFactory() +TCPSocketFactory::~TCPSocketFactory() { // do nothing } 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( + ARCH->plugin().invoke(s_networkSecurity, "getSocket", args)); + } + else { + socket = new TCPSocket(m_events, m_socketMultiplexer); + } + + return socket; } 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( + ARCH->plugin().invoke(s_networkSecurity, "getListenSocket", args)); + } + else { + socket = new TCPListenSocket(m_events, m_socketMultiplexer); + } + + return socket; } diff --git a/src/lib/net/TCPSocketFactory.h b/src/lib/net/TCPSocketFactory.h index f74ee6dc..714ded5b 100644 --- a/src/lib/net/TCPSocketFactory.h +++ b/src/lib/net/TCPSocketFactory.h @@ -24,16 +24,18 @@ class IEventQueue; class SocketMultiplexer; //! Socket factory for TCP sockets -class CTCPSocketFactory : public ISocketFactory { +class TCPSocketFactory : public ISocketFactory { public: - CTCPSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer); - virtual ~CTCPSocketFactory(); + TCPSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer); + virtual ~TCPSocketFactory(); // ISocketFactory overrides - virtual IDataSocket* create() const; - virtual IListenSocket* createListen() const; + virtual IDataSocket* + create(bool secure) const; + virtual IListenSocket* + createListen(bool secure) const; private: IEventQueue* m_events; - SocketMultiplexer* m_socketMultiplexer; + SocketMultiplexer* m_socketMultiplexer; }; diff --git a/src/plugin/CMakeLists.txt b/src/lib/plugin/CMakeLists.txt similarity index 97% rename from src/plugin/CMakeLists.txt rename to src/lib/plugin/CMakeLists.txt index 09b15520..b835ad6a 100644 --- a/src/plugin/CMakeLists.txt +++ b/src/lib/plugin/CMakeLists.txt @@ -14,6 +14,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +add_subdirectory(ns) + if (WIN32) add_subdirectory(winmmjoy) endif() diff --git a/src/lib/plugin/ns/CMakeLists.txt b/src/lib/plugin/ns/CMakeLists.txt new file mode 100644 index 00000000..0db61b60 --- /dev/null +++ b/src/lib/plugin/ns/CMakeLists.txt @@ -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 . + +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() diff --git a/src/lib/plugin/ns/SecureListenSocket.cpp b/src/lib/plugin/ns/SecureListenSocket.cpp new file mode 100644 index 00000000..b7c1f382 --- /dev/null +++ b/src/lib/plugin/ns/SecureListenSocket.cpp @@ -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 . + */ + +#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( + this, &TCPListenSocket::serviceListening, + m_socket, true, false)); + } + return dynamic_cast(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); + } +} diff --git a/src/lib/io/IStreamFilterFactory.h b/src/lib/plugin/ns/SecureListenSocket.h similarity index 56% rename from src/lib/io/IStreamFilterFactory.h rename to src/lib/plugin/ns/SecureListenSocket.h index 334f5d7b..15166340 100644 --- a/src/lib/io/IStreamFilterFactory.h +++ b/src/lib/plugin/ns/SecureListenSocket.h @@ -1,7 +1,6 @@ /* * synergy -- mouse and keyboard sharing utility - * Copyright (C) 2012 Synergy Si Ltd. - * Copyright (C) 2002 Chris Schoeneman + * 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 @@ -18,21 +17,26 @@ #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 -/*! -This interface provides factory methods to create stream filters. -*/ -class IStreamFilterFactory : public IInterface { +class SecureListenSocket : public TCPListenSocket{ public: - //! Create filter - /*! - Create and return a stream filter on \p stream. The caller must - delete the returned object. - */ - virtual synergy::IStream* - create(synergy::IStream* stream, bool adoptStream) = 0; + SecureListenSocket(IEventQueue* events, + SocketMultiplexer* socketMultiplexer); + ~SecureListenSocket(); + + // IListenSocket overrides + virtual IDataSocket* + accept(); + void deleteSocket(void*); + +private: + typedef std::set SecureSocketSet; + + SecureSocketSet m_secureSocketSet; }; diff --git a/src/lib/plugin/ns/SecureSocket.cpp b/src/lib/plugin/ns/SecureSocket.cpp new file mode 100644 index 00000000..c262a362 --- /dev/null +++ b/src/lib/plugin/ns/SecureSocket.cpp @@ -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 . + */ + +#include "SecureSocket.h" + +#include "net/TSocketMultiplexerMethodJob.h" +#include "net/TCPSocket.h" +#include "mt/Lock.h" +#include "arch/XArch.h" +#include "base/Log.h" + +#include +#include +#include +#include +#include + +// +// 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( + this, &SecureSocket::serviceConnect, + getSocket(), isReadable(), isWritable())); +} + +void +SecureSocket::secureAccept() +{ + setJob(new TSocketMultiplexerMethodJob( + 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(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(getSocket()->m_socket)); +#elif SYSAPI_UNIX + retry = secureAccept(getSocket()->m_fd); +#endif + + return retry ? job : newJob(); +} diff --git a/src/lib/plugin/ns/SecureSocket.h b/src/lib/plugin/ns/SecureSocket.h new file mode 100644 index 00000000..7d09ed21 --- /dev/null +++ b/src/lib/plugin/ns/SecureSocket.h @@ -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 . + */ + +#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; +}; diff --git a/src/lib/plugin/ns/ns.cpp b/src/lib/plugin/ns/ns.cpp new file mode 100644 index 00000000..84e20b1e --- /dev/null +++ b/src/lib/plugin/ns/ns.cpp @@ -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 . + */ + +#include "ns.h" + +#include "SecureSocket.h" +#include "SecureListenSocket.h" +#include "arch/Arch.h" +#include "base/Log.h" + +#include + +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)); + } + + if (g_arch == NULL) { + g_arch = new Arch(reinterpret_cast(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(args[0]); + arg2 = reinterpret_cast(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; + } +} + +} \ No newline at end of file diff --git a/src/lib/plugin/ns/ns.h b/src/lib/plugin/ns/ns.h new file mode 100644 index 00000000..9e725166 --- /dev/null +++ b/src/lib/plugin/ns/ns.h @@ -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 . + */ + +#pragma once + +#if defined _WIN32 +#define WIN32_LEAN_AND_MEAN +#include + +#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(); + +} diff --git a/src/plugin/winmmjoy/CMakeLists.txt b/src/lib/plugin/winmmjoy/CMakeLists.txt similarity index 88% rename from src/plugin/winmmjoy/CMakeLists.txt rename to src/lib/plugin/winmmjoy/CMakeLists.txt index 5318cac4..a0dcb997 100644 --- a/src/plugin/winmmjoy/CMakeLists.txt +++ b/src/lib/plugin/winmmjoy/CMakeLists.txt @@ -27,6 +27,6 @@ add_custom_command( TARGET winmmjoy POST_BUILD COMMAND xcopy /Y /Q - ..\\..\\..\\..\\lib\\${CMAKE_CFG_INTDIR}\\winmmjoy.* - ..\\..\\..\\..\\bin\\${CMAKE_CFG_INTDIR}\\plugins\\ + ..\\..\\..\\..\\..\\lib\\${CMAKE_CFG_INTDIR}\\winmmjoy.* + ..\\..\\..\\..\\..\\bin\\${CMAKE_CFG_INTDIR}\\plugins\\ ) diff --git a/src/plugin/winmmjoy/winmmjoy.cpp b/src/lib/plugin/winmmjoy/winmmjoy.cpp similarity index 95% rename from src/plugin/winmmjoy/winmmjoy.cpp rename to src/lib/plugin/winmmjoy/winmmjoy.cpp index 96fc6670..da4739d3 100644 --- a/src/plugin/winmmjoy/winmmjoy.cpp +++ b/src/lib/plugin/winmmjoy/winmmjoy.cpp @@ -36,22 +36,23 @@ static void (*s_log)(const char*) = NULL; extern "C" { +void +init(void* log, void* arch) +{ +} + int -init(void (*sendEvent)(const char*, void*), void (*log)(const char*)) +initEvent(void (*sendEvent)(const char*, void*)) { s_sendEvent = sendEvent; - s_log = log; - LOG("init"); CreateThread(NULL, 0, mainLoop, NULL, 0, NULL); return 0; } -int +void cleanup() { - LOG("cleanup"); s_running = false; - return 0; } } diff --git a/src/plugin/winmmjoy/winmmjoy.h b/src/lib/plugin/winmmjoy/winmmjoy.h similarity index 92% rename from src/plugin/winmmjoy/winmmjoy.h rename to src/lib/plugin/winmmjoy/winmmjoy.h index 9addac0f..bd10896f 100644 --- a/src/plugin/winmmjoy/winmmjoy.h +++ b/src/lib/plugin/winmmjoy/winmmjoy.h @@ -29,8 +29,9 @@ extern "C" { -WINMMJOY_API int init(void (*sendEvent)(const char*, void*), void (*log)(const char*)); -WINMMJOY_API int cleanup(); +WINMMJOY_API void init(void* log, void* arch); +WINMMJOY_API int initEvent(void (*sendEvent)(const char*, void*)); +WINMMJOY_API void cleanup(); } diff --git a/src/lib/server/BaseClientProxy.h b/src/lib/server/BaseClientProxy.h index 55c9f1a5..1371d089 100644 --- a/src/lib/server/BaseClientProxy.h +++ b/src/lib/server/BaseClientProxy.h @@ -21,6 +21,8 @@ #include "synergy/IClient.h" #include "base/String.h" +namespace synergy { class IStream; } + //! Generic proxy for client or primary class BaseClientProxy : public IClient { public: @@ -82,6 +84,8 @@ public: size_t size) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0; virtual String getName() const; + virtual synergy::IStream* + getStream() const = 0; private: String m_name; diff --git a/src/lib/server/ClientListener.cpp b/src/lib/server/ClientListener.cpp index a486774d..946c7705 100644 --- a/src/lib/server/ClientListener.cpp +++ b/src/lib/server/ClientListener.cpp @@ -27,7 +27,6 @@ #include "net/XSocket.h" #include "io/CryptoStream.h" #include "io/CryptoOptions.h" -#include "io/IStreamFilterFactory.h" #include "base/Log.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" @@ -36,13 +35,17 @@ // ClientListener // +#if defined _WIN32 +static const char s_networkSecurity[] = { "ns" }; +#else +static const char s_networkSecurity[] = { "libns" }; +#endif + ClientListener::ClientListener(const NetworkAddress& address, ISocketFactory* socketFactory, - IStreamFilterFactory* streamFilterFactory, const CryptoOptions& crypto, IEventQueue* events) : m_socketFactory(socketFactory), - m_streamFilterFactory(streamFilterFactory), m_server(NULL), m_crypto(crypto), m_events(events) @@ -51,22 +54,21 @@ ClientListener::ClientListener(const NetworkAddress& address, try { // 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 LOG((CLOG_DEBUG1 "binding listen socket")); m_listen->bind(address); } catch (XSocketAddressInUse&) { - delete m_listen; + cleanupListenSocket(); delete m_socketFactory; - delete m_streamFilterFactory; throw; } catch (XBase&) { - delete m_listen; + cleanupListenSocket(); delete m_socketFactory; - delete m_streamFilterFactory; throw; } LOG((CLOG_DEBUG1 "listening for clients")); @@ -102,9 +104,8 @@ ClientListener::~ClientListener() } m_events->removeHandler(m_events->forIListenSocket().connecting(), m_listen); - delete m_listen; + cleanupListenSocket(); delete m_socketFactory; - delete m_streamFilterFactory; } void @@ -114,6 +115,12 @@ ClientListener::setServer(Server* server) m_server = server; } +void +ClientListener::deleteSocket(void* socket) +{ + m_listen->deleteSocket(socket); +} + ClientProxy* ClientListener::getNextClient() { @@ -130,17 +137,18 @@ void ClientListener::handleClientConnecting(const Event&, void*) { // accept client connection - synergy::IStream* stream = m_listen->accept(); + IDataSocket* socket = m_listen->accept(); + synergy::IStream* stream = socket; + 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 PacketStreamFilter(m_events, stream, true); + bool adopt = !m_useSecureNetwork; + stream = new PacketStreamFilter(m_events, stream, adopt); if (m_crypto.m_mode != kDisabled) { CryptoStream* cryptoStream = new CryptoStream( @@ -150,6 +158,12 @@ ClientListener::handleClientConnecting(const Event&, void*) assert(m_server != NULL); + if (m_useSecureNetwork) { + while(!socket->isReady()) { + ARCH->sleep(.5f); + } + } + // create proxy for unknown client ClientProxyUnknown* client = new ClientProxyUnknown(stream, 30.0, m_server, m_events); m_newClients.insert(client); @@ -174,6 +188,7 @@ ClientListener::handleUnknownClient(const Event&, void* vclient) // get the real client proxy and install it ClientProxy* client = unknownClient->orphanClientProxy(); + bool handshakeOk = true; if (client != NULL) { // handshake was successful m_waitingClients.push_back(client); @@ -185,12 +200,25 @@ ClientListener::handleUnknownClient(const Event&, void* vclient) &ClientListener::handleClientDisconnected, client)); } + else { + handshakeOk = false; + } // now finished with unknown client m_events->removeHandler(m_events->forClientProxyUnknown().success(), client); m_events->removeHandler(m_events->forClientProxyUnknown().failure(), client); m_newClients.erase(unknownClient); + PacketStreamFilter* streamFileter = dynamic_cast(unknownClient->getStream()); + IDataSocket* socket = NULL; + if (streamFileter != NULL) { + socket = dynamic_cast(streamFileter->getStream()); + } + delete unknownClient; + + if (m_useSecureNetwork && !handshakeOk) { + deleteSocket(socket); + } } 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); + } +} diff --git a/src/lib/server/ClientListener.h b/src/lib/server/ClientListener.h index a37f2132..b92887aa 100644 --- a/src/lib/server/ClientListener.h +++ b/src/lib/server/ClientListener.h @@ -30,7 +30,6 @@ class ClientProxyUnknown; class NetworkAddress; class IListenSocket; class ISocketFactory; -class IStreamFilterFactory; class Server; class IEventQueue; @@ -39,7 +38,6 @@ public: // The factories are adopted. ClientListener(const NetworkAddress&, ISocketFactory*, - IStreamFilterFactory*, const CryptoOptions& crypto, IEventQueue* events); ~ClientListener(); @@ -51,6 +49,8 @@ public: //@} + void deleteSocket(void* socket); + //! @name accessors //@{ @@ -63,7 +63,7 @@ public: ClientProxy* getNextClient(); //! Get server which owns this listener - Server* getServer() { return m_server; } + Server* getServer() { return m_server; } //@} @@ -73,16 +73,18 @@ private: void handleUnknownClient(const Event&, void*); void handleClientDisconnected(const Event&, void*); + void cleanupListenSocket(); + private: typedef std::set NewClients; typedef std::deque WaitingClients; IListenSocket* m_listen; ISocketFactory* m_socketFactory; - IStreamFilterFactory* m_streamFilterFactory; NewClients m_newClients; WaitingClients m_waitingClients; - Server* m_server; + Server* m_server; CryptoOptions m_crypto; IEventQueue* m_events; + bool m_useSecureNetwork; }; diff --git a/src/lib/server/ClientProxy.h b/src/lib/server/ClientProxy.h index 1007ba58..1cadad25 100644 --- a/src/lib/server/ClientProxy.h +++ b/src/lib/server/ClientProxy.h @@ -52,7 +52,7 @@ public: Returns a crypto stream if the user has this enabled, otherwise returns the original stream passed to the c'tor. */ - synergy::IStream* getStream() const; + synergy::IStream* getStream() const; //@} diff --git a/src/lib/server/ClientProxyUnknown.h b/src/lib/server/ClientProxyUnknown.h index 060b0000..2907c9cf 100644 --- a/src/lib/server/ClientProxyUnknown.h +++ b/src/lib/server/ClientProxyUnknown.h @@ -43,6 +43,9 @@ public: */ ClientProxy* orphanClientProxy(); + //! Get the stream + synergy::IStream* getStream() { return m_stream; } + //@} private: @@ -63,6 +66,6 @@ private: EventQueueTimer* m_timer; ClientProxy* m_proxy; bool m_ready; - Server* m_server; + Server* m_server; IEventQueue* m_events; }; diff --git a/src/lib/server/PrimaryClient.h b/src/lib/server/PrimaryClient.h index f22f4464..b7c64a4f 100644 --- a/src/lib/server/PrimaryClient.h +++ b/src/lib/server/PrimaryClient.h @@ -146,6 +146,9 @@ public: virtual void sendDragInfo(UInt32 fileCount, const char* info, size_t size); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); + virtual synergy::IStream* + getStream() const { return NULL; } + private: synergy::Screen* m_screen; bool m_clipboardDirty[kClipboardEnd]; diff --git a/src/lib/server/Server.cpp b/src/lib/server/Server.cpp index c260583e..f8b944f8 100644 --- a/src/lib/server/Server.cpp +++ b/src/lib/server/Server.cpp @@ -21,6 +21,7 @@ #include "server/ClientProxy.h" #include "server/ClientProxyUnknown.h" #include "server/PrimaryClient.h" +#include "server/ClientListener.h" #include "synergy/IPlatformScreen.h" #include "synergy/DropHelper.h" #include "synergy/option_types.h" @@ -30,6 +31,8 @@ #include "synergy/FileChunker.h" #include "synergy/KeyState.h" #include "synergy/Screen.h" +#include "synergy/PacketStreamFilter.h" +#include "net/TCPSocket.h" #include "net/IDataSocket.h" #include "net/IListenSocket.h" #include "net/XSocket.h" @@ -1358,7 +1361,11 @@ Server::handleClientDisconnected(const Event&, void* vclient) BaseClientProxy* client = reinterpret_cast(vclient); removeActiveClient(client); removeOldClient(client); + + PacketStreamFilter* streamFileter = dynamic_cast(client->getStream()); + TCPSocket* socket = dynamic_cast(streamFileter->getStream()); delete client; + m_clientListener->deleteSocket(socket); } void @@ -1368,7 +1375,10 @@ Server::handleClientCloseTimeout(const Event&, void* vclient) BaseClientProxy* client = reinterpret_cast(vclient); LOG((CLOG_NOTE "forced disconnection of client \"%s\"", getName(client).c_str())); removeOldClient(client); + PacketStreamFilter* streamFileter = dynamic_cast(client->getStream()); + TCPSocket* socket = dynamic_cast(streamFileter->getStream()); delete client; + m_clientListener->deleteSocket(socket); } void diff --git a/src/lib/server/Server.h b/src/lib/server/Server.h index d1efccb6..f3302ae1 100644 --- a/src/lib/server/Server.h +++ b/src/lib/server/Server.h @@ -39,6 +39,7 @@ class InputFilter; namespace synergy { class Screen; } class IEventQueue; class Thread; +class ClientListener; //! Synergy server /*! @@ -154,6 +155,9 @@ public: //! Received dragging information from client void dragInfoReceived(UInt32 fileNum, String content); + + //! Store ClientListener pointer + void setListener(ClientListener* p) { m_clientListener = p; } //@} //! @name accessors @@ -412,7 +416,7 @@ private: SInt32 m_xDelta2, m_yDelta2; // current configuration - Config* m_config; + Config* m_config; // input filter (from m_config); InputFilter* m_inputFilter; @@ -458,7 +462,7 @@ private: bool m_lockedToScreen; // server screen - synergy::Screen* m_screen; + synergy::Screen* m_screen; IEventQueue* m_events; @@ -466,12 +470,14 @@ private: size_t m_expectedFileSize; String m_receivedFileData; DragFileList m_dragFileList; - Thread* m_sendFileThread; - Thread* m_writeToDropDirThread; + Thread* m_sendFileThread; + Thread* m_writeToDropDirThread; String m_dragFileExt; bool m_ignoreFileTransfer; bool m_enableDragDrop; - Thread* m_getDragInfoThread; + Thread* m_getDragInfoThread; bool m_waitDragInfoThread; + + ClientListener* m_clientListener; }; diff --git a/src/lib/synergy/ClientApp.cpp b/src/lib/synergy/ClientApp.cpp index 530dd525..a6b297ac 100644 --- a/src/lib/synergy/ClientApp.cpp +++ b/src/lib/synergy/ClientApp.cpp @@ -326,7 +326,7 @@ ClientApp::handleClientDisconnected(const Event&, void*) m_events->addEvent(Event(Event::kQuit)); } else if (!m_suspended) { - m_client->connect(); + scheduleClientRestart(nextRestartTimeout()); } updateStatus(); } @@ -340,8 +340,7 @@ ClientApp::openClient(const String& name, const NetworkAddress& address, m_events, name, address, - new CTCPSocketFactory(m_events, getSocketMultiplexer()), - NULL, + new TCPSocketFactory(m_events, getSocketMultiplexer()), screen, crypto, args().m_enableDragDrop); @@ -458,6 +457,11 @@ ClientApp::mainLoop() SocketMultiplexer 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 appUtil().startNode(); @@ -467,8 +471,8 @@ ClientApp::mainLoop() initIpcClient(); } - // load all available plugins. - ARCH->plugin().init(m_clientScreen->getEventTarget(), m_events); + // init event for all available plugins. + ARCH->plugin().initEvent(m_clientScreen->getEventTarget(), m_events); // run event loop. if startClient() failed we're supposed to retry // later. the timer installed by startClient() will take care of @@ -504,6 +508,9 @@ ClientApp::mainLoop() cleanupIpcClient(); } + // unload all plugins. + ARCH->plugin().unload(); + return kExitSuccess; } diff --git a/src/lib/synergy/DragInformation.cpp b/src/lib/synergy/DragInformation.cpp index 0373183a..7fb2be3c 100644 --- a/src/lib/synergy/DragInformation.cpp +++ b/src/lib/synergy/DragInformation.cpp @@ -101,7 +101,7 @@ DragInformation::getDragFileExtension(String filename) int DragInformation::setupDragInfo(DragFileList& fileList, String& output) { - int size = fileList.size(); + int size = static_cast(fileList.size()); for (int i = 0; i < size; ++i) { output.append(fileList.at(i).getFilename()); output.append(","); diff --git a/src/lib/synergy/ServerApp.cpp b/src/lib/synergy/ServerApp.cpp index 9c4d29c7..bd1be71a 100644 --- a/src/lib/synergy/ServerApp.cpp +++ b/src/lib/synergy/ServerApp.cpp @@ -338,8 +338,8 @@ void ServerApp::stopServer() { if (m_serverState == kStarted) { - closeClientListener(m_listener); closeServer(m_server); + closeClientListener(m_listener); m_server = NULL; m_listener = NULL; m_serverState = kInitialized; @@ -543,6 +543,7 @@ ServerApp::startServer() listener = openClientListener(args().m_config->getSynergyAddress()); m_server = openServer(*args().m_config, m_primaryClient); listener->setServer(m_server); + m_server->setListener(listener); m_listener = listener; updateStatus(); LOG((CLOG_NOTE "started server, waiting for clients")); @@ -631,8 +632,7 @@ ServerApp::openClientListener(const NetworkAddress& address) { ClientListener* listen = new ClientListener( address, - new CTCPSocketFactory(m_events, getSocketMultiplexer()), - NULL, + new TCPSocketFactory(m_events, getSocketMultiplexer()), args().m_crypto, m_events); @@ -707,6 +707,11 @@ ServerApp::mainLoop() 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 appUtil().startNode(); @@ -716,8 +721,8 @@ ServerApp::mainLoop() initIpcClient(); } - // load all available plugins. - ARCH->plugin().init(m_serverScreen->getEventTarget(), m_events); + // init event for all available plugins. + ARCH->plugin().initEvent(m_serverScreen->getEventTarget(), m_events); // handle hangup signal by reloading the server's configuration ARCH->setSignalHandler(Arch::kHANGUP, &reloadSignalHandler, NULL); @@ -775,6 +780,9 @@ ServerApp::mainLoop() cleanupIpcClient(); } + // unload all plugins. + ARCH->plugin().unload(); + return kExitSuccess; } diff --git a/src/test/integtests/net/NetworkTests.cpp b/src/test/integtests/net/NetworkTests.cpp index 8ff59ef7..74349718 100644 --- a/src/test/integtests/net/NetworkTests.cpp +++ b/src/test/integtests/net/NetworkTests.cpp @@ -115,8 +115,8 @@ TEST_F(NetworkTests, sendToClient_mockData) // server SocketMultiplexer serverSocketMultiplexer; - CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); - ClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); + TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, cryptoOptions, &m_events); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; @@ -137,12 +137,12 @@ TEST_F(NetworkTests, sendToClient_mockData) // client NiceMock clientScreen; 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, 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.forIScreen().fileRecieveCompleted(), &client, @@ -168,8 +168,8 @@ TEST_F(NetworkTests, sendToClient_mockFile) // server SocketMultiplexer serverSocketMultiplexer; - CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); - ClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); + TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, cryptoOptions, &m_events); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; @@ -190,12 +190,12 @@ TEST_F(NetworkTests, sendToClient_mockFile) // client NiceMock clientScreen; 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, 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.forIScreen().fileRecieveCompleted(), &client, @@ -221,8 +221,8 @@ TEST_F(NetworkTests, sendToServer_mockData) // server SocketMultiplexer serverSocketMultiplexer; - CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); - ClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); + TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, cryptoOptions, &m_events); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; @@ -238,12 +238,12 @@ TEST_F(NetworkTests, sendToServer_mockData) // client NiceMock clientScreen; 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, 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.forClientListener().connected(), &listener, @@ -274,8 +274,8 @@ TEST_F(NetworkTests, sendToServer_mockFile) // server SocketMultiplexer serverSocketMultiplexer; - CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); - ClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); + TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); + ClientListener listener(serverAddress, serverSocketFactory, cryptoOptions, &m_events); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; @@ -291,12 +291,12 @@ TEST_F(NetworkTests, sendToServer_mockFile) // client NiceMock clientScreen; 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, 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.forClientListener().connected(), &listener,