From c368013f133aa932a14046c42217fc90bbeacaba Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Tue, 16 Jul 2013 19:02:30 +0000 Subject: [PATCH] Patch by Jerry for issue 46: - Unit test for sending file data from server to client. - Removed singleton pattern from CSocketMultiplexer for easier unit testing. - Incremented protocol version from 1.4 to 1.5 (new file chunk message). - Storing pointer to CConfig instead of copying in CServer (so we can mock it). - Created a common event queue for testing (timeout, quit event, etc). - Fixed code style. --- src/lib/base/CEventTypes.cpp | 2 + src/lib/base/CEventTypes.h | 14 +- src/lib/client/CClient.cpp | 39 +++- src/lib/client/CClient.h | 17 +- src/lib/client/CServerProxy.cpp | 30 +++ src/lib/client/CServerProxy.h | 1 + src/lib/ipc/CIpcClient.cpp | 8 +- src/lib/ipc/CIpcClient.h | 5 +- src/lib/ipc/CIpcServer.cpp | 8 +- src/lib/ipc/CIpcServer.h | 5 +- src/lib/net/CSocketMultiplexer.cpp | 15 -- src/lib/net/CSocketMultiplexer.h | 2 - src/lib/net/CTCPListenSocket.cpp | 15 +- src/lib/net/CTCPListenSocket.h | 4 +- src/lib/net/CTCPSocket.cpp | 14 +- src/lib/net/CTCPSocket.h | 6 +- src/lib/net/CTCPSocketFactory.cpp | 9 +- src/lib/net/CTCPSocketFactory.h | 4 +- src/lib/server/CBaseClientProxy.h | 1 + src/lib/server/CClientListener.h | 5 +- src/lib/server/CClientProxy.h | 1 + src/lib/server/CClientProxy1_0.cpp | 7 + src/lib/server/CClientProxy1_0.h | 1 + src/lib/server/CClientProxy1_5.cpp | 56 ++++++ src/lib/server/CClientProxy1_5.h | 32 +++ src/lib/server/CClientProxyUnknown.cpp | 5 + src/lib/server/CConfig.h | 9 +- src/lib/server/CInputFilter.h | 6 +- src/lib/server/CMakeLists.txt | 2 + src/lib/server/CPrimaryClient.cpp | 9 +- src/lib/server/CPrimaryClient.h | 15 +- src/lib/server/CServer.cpp | 60 ++++-- src/lib/server/CServer.h | 13 +- src/lib/synergy/CApp.cpp | 2 +- src/lib/synergy/CApp.h | 7 +- src/lib/synergy/CClientApp.cpp | 9 +- src/lib/synergy/CDaemonApp.cpp | 2 +- src/lib/synergy/CScreen.cpp | 7 +- src/lib/synergy/CScreen.h | 14 +- src/lib/synergy/CServerApp.cpp | 10 +- src/lib/synergy/CServerApp.h | 2 +- src/lib/synergy/INode.h | 2 + src/lib/synergy/ProtocolTypes.cpp | 1 + src/lib/synergy/ProtocolTypes.h | 9 +- src/test/integtests/CIpcTests.cpp | 77 ++----- src/test/integtests/CMakeLists.txt | 11 +- src/test/integtests/CTestEventQueue.cpp | 52 +++++ src/test/integtests/CTestEventQueue.h | 38 ++++ src/test/integtests/NetworkTests.cpp | 188 ++++++++++++++++++ .../platform/CMSWindowsKeyStateTests.cpp | 4 +- src/test/unittests/CMakeLists.txt | 4 + src/test/unittests/io/CMockCryptoStream.h | 1 - src/test/unittests/server/CMockConfig.h | 31 +++ src/test/unittests/server/CMockInputFilter.h | 29 +++ .../unittests/server/CMockPrimaryClient.h | 40 ++++ src/test/unittests/synergy/CMockScreen.h | 35 ++++ 56 files changed, 830 insertions(+), 165 deletions(-) create mode 100644 src/lib/server/CClientProxy1_5.cpp create mode 100644 src/lib/server/CClientProxy1_5.h create mode 100644 src/test/integtests/CTestEventQueue.cpp create mode 100644 src/test/integtests/CTestEventQueue.h create mode 100644 src/test/integtests/NetworkTests.cpp create mode 100644 src/test/unittests/server/CMockConfig.h create mode 100644 src/test/unittests/server/CMockInputFilter.h create mode 100644 src/test/unittests/server/CMockPrimaryClient.h create mode 100644 src/test/unittests/synergy/CMockScreen.h diff --git a/src/lib/base/CEventTypes.cpp b/src/lib/base/CEventTypes.cpp index 68d70b73..6dd6e404 100644 --- a/src/lib/base/CEventTypes.cpp +++ b/src/lib/base/CEventTypes.cpp @@ -180,6 +180,8 @@ REGISTER_EVENT(IScreen, shapeChanged) REGISTER_EVENT(IScreen, clipboardGrabbed) REGISTER_EVENT(IScreen, suspend) REGISTER_EVENT(IScreen, resume) +REGISTER_EVENT(IScreen, fileChunkSending) +REGISTER_EVENT(IScreen, fileRecieveComplete) // // ISecondaryScreen diff --git a/src/lib/base/CEventTypes.h b/src/lib/base/CEventTypes.h index 74679f1e..31219b5e 100644 --- a/src/lib/base/CEventTypes.h +++ b/src/lib/base/CEventTypes.h @@ -647,7 +647,9 @@ public: m_shapeChanged(CEvent::kUnknown), m_clipboardGrabbed(CEvent::kUnknown), m_suspend(CEvent::kUnknown), - m_resume(CEvent::kUnknown) { } + m_resume(CEvent::kUnknown), + m_fileChunkSending(CEvent::kUnknown), + m_fileRecieveComplete(CEvent::kUnknown) { } //! @name accessors //@{ @@ -683,11 +685,17 @@ public: //! Get resume event type /*! - Returns the suspend event type. This is sent whenever the system wakes + Returns the resume event type. This is sent whenever the system wakes up or a user session is activated (fast user switching). */ CEvent::Type resume(); + //! Sending a file chunk + CEvent::Type fileChunkSending(); + + //! Completed receiving a file + CEvent::Type fileRecieveComplete(); + //@} private: @@ -696,6 +704,8 @@ private: CEvent::Type m_clipboardGrabbed; CEvent::Type m_suspend; CEvent::Type m_resume; + CEvent::Type m_fileChunkSending; + CEvent::Type m_fileRecieveComplete; }; class ISecondaryScreenEvents : public CEventTypes { diff --git a/src/lib/client/CClient.cpp b/src/lib/client/CClient.cpp index c874a969..fdf34721 100644 --- a/src/lib/client/CClient.cpp +++ b/src/lib/client/CClient.cpp @@ -30,11 +30,12 @@ #include "CLog.h" #include "IEventQueue.h" #include "TMethodEventJob.h" -#include -#include #include "CArch.h" #include "IPlatformScreen.h" #include "CCryptoStream.h" +#include +#include +#include // // CClient @@ -83,6 +84,10 @@ CClient::CClient(IEventQueue* events, getEventTarget(), new TMethodEventJob(this, &CClient::handleGameDeviceFeedback)); + m_events->adoptHandler(m_events->forIScreen().fileChunkSending(), + this, + new TMethodEventJob(this, + &CClient::handleFileChunkSending)); } CClient::~CClient() @@ -728,3 +733,33 @@ CClient::handleGameDeviceFeedback(const CEvent& event, void*) m_server->onGameDeviceFeedback(info->m_id, info->m_m1, info->m_m2); } + +void +CClient::handleFileChunkSending(const CEvent& event, void*) +{ +} + +void +CClient::clearReceivedFileData() +{ + m_receivedFileData.clear(); +} + +void +CClient::setExpectedFileSize(CString data) +{ + std::istringstream iss(data); + iss >> m_expectedFileSize; +} + +void +CClient::fileChunkReceived(CString data) +{ + m_receivedFileData += data; +} + +bool +CClient::isReceivedFileSizeValid() +{ + return m_expectedFileSize == m_receivedFileData.size(); +} diff --git a/src/lib/client/CClient.h b/src/lib/client/CClient.h index 05a30566..c4db7e9c 100644 --- a/src/lib/client/CClient.h +++ b/src/lib/client/CClient.h @@ -64,7 +64,7 @@ public: ~CClient(); #ifdef TEST_ENV - CClient() : m_mock(true), m_events(NULL) { } + CClient() : m_mock(true) { } #endif //! @name manipulators @@ -92,6 +92,18 @@ public: //! Set crypto IV for decryption virtual void setDecryptIv(const UInt8* iv); + //! Clears the file buffer + void clearReceivedFileData(); + + //! Set the expected size of receiving file + void setExpectedFileSize(CString data); + + //! Received a chunk of file data + void fileChunkReceived(CString data); + + //! Return true if recieved file size is valid + bool isReceivedFileSizeValid(); + //@} //! @name accessors //@{ @@ -175,6 +187,7 @@ private: void handleResume(const CEvent& event, void*); void handleGameDeviceTimingResp(const CEvent& event, void*); void handleGameDeviceFeedback(const CEvent& event, void*); + void handleFileChunkSending(const CEvent&, void*); public: bool m_mock; @@ -199,6 +212,8 @@ private: IEventQueue* m_events; CCryptoStream* m_cryptoStream; CCryptoOptions m_crypto; + std::size_t m_expectedFileSize; + CString m_receivedFileData; }; #endif diff --git a/src/lib/client/CServerProxy.cpp b/src/lib/client/CServerProxy.cpp index b7291b92..dff281ce 100644 --- a/src/lib/client/CServerProxy.cpp +++ b/src/lib/client/CServerProxy.cpp @@ -309,6 +309,10 @@ CServerProxy::parseMessage(const UInt8* code) cryptoIv(); } + else if (memcmp(code, kMsgDFileTransfer, 4) == 0) { + fileChunkReceived(); + } + else if (memcmp(code, kMsgCClose, 4) == 0) { // server wants us to hangup LOG((CLOG_DEBUG1 "recv close")); @@ -930,3 +934,29 @@ CServerProxy::infoAcknowledgment() LOG((CLOG_DEBUG1 "recv info acknowledgment")); m_ignoreMouse = false; } + +void CServerProxy::fileChunkReceived() +{ + // parse + UInt8 mark; + CString content; + CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content); + + switch (mark) { + case '0': + LOG((CLOG_DEBUG2 "recv file data: file size = %s", content)); + m_client->clearReceivedFileData(); + m_client->setExpectedFileSize(content); + break; + + case '1': + LOG((CLOG_DEBUG2 "recv file data: chunck size = %i", content.size())); + m_client->fileChunkReceived(content); + break; + + case '2': + LOG((CLOG_DEBUG2 "file data transfer finished")); + m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), m_client)); + break; + } +} diff --git a/src/lib/client/CServerProxy.h b/src/lib/client/CServerProxy.h index 13735ad3..a1afa4e4 100644 --- a/src/lib/client/CServerProxy.h +++ b/src/lib/client/CServerProxy.h @@ -105,6 +105,7 @@ private: void setOptions(); void queryInfo(); void infoAcknowledgment(); + void fileChunkReceived(); private: typedef EResult (CServerProxy::*MessageParser)(const UInt8*); diff --git a/src/lib/ipc/CIpcClient.cpp b/src/lib/ipc/CIpcClient.cpp index b7fa31fb..30a1bba6 100644 --- a/src/lib/ipc/CIpcClient.cpp +++ b/src/lib/ipc/CIpcClient.cpp @@ -26,19 +26,19 @@ // CIpcClient // -CIpcClient::CIpcClient(IEventQueue* events) : +CIpcClient::CIpcClient(IEventQueue* events, CSocketMultiplexer* socketMultiplexer) : m_serverAddress(CNetworkAddress(IPC_HOST, IPC_PORT)), m_server(nullptr), - m_socket(events), + m_socket(events, socketMultiplexer), m_events(events) { init(); } -CIpcClient::CIpcClient(IEventQueue* events, int port) : +CIpcClient::CIpcClient(IEventQueue* events, CSocketMultiplexer* socketMultiplexer, int port) : m_serverAddress(CNetworkAddress(IPC_HOST, port)), m_server(nullptr), - m_socket(events), + m_socket(events, socketMultiplexer), m_events(events) { init(); diff --git a/src/lib/ipc/CIpcClient.h b/src/lib/ipc/CIpcClient.h index f3cab051..b486cce4 100644 --- a/src/lib/ipc/CIpcClient.h +++ b/src/lib/ipc/CIpcClient.h @@ -25,6 +25,7 @@ class CIpcServerProxy; class CIpcMessage; class IEventQueue; +class CSocketMultiplexer; //! IPC client for communication between daemon and GUI. /*! @@ -32,8 +33,8 @@ class IEventQueue; */ class CIpcClient { public: - CIpcClient(IEventQueue* events); - CIpcClient(IEventQueue* events, int port); + CIpcClient(IEventQueue* events, CSocketMultiplexer* socketMultiplexer); + CIpcClient(IEventQueue* events, CSocketMultiplexer* socketMultiplexer, int port); virtual ~CIpcClient(); //! @name manipulators diff --git a/src/lib/ipc/CIpcServer.cpp b/src/lib/ipc/CIpcServer.cpp index 037f0c8a..cd91ab68 100644 --- a/src/lib/ipc/CIpcServer.cpp +++ b/src/lib/ipc/CIpcServer.cpp @@ -31,17 +31,17 @@ // CIpcServer // -CIpcServer::CIpcServer(IEventQueue* events) : +CIpcServer::CIpcServer(IEventQueue* events, CSocketMultiplexer* socketMultiplexer) : m_events(events), - m_socket(events), + m_socket(events, socketMultiplexer), m_address(CNetworkAddress(IPC_HOST, IPC_PORT)) { init(); } -CIpcServer::CIpcServer(IEventQueue* events, int port) : +CIpcServer::CIpcServer(IEventQueue* events, CSocketMultiplexer* socketMultiplexer, int port) : m_events(events), - m_socket(events), + m_socket(events, socketMultiplexer), m_address(CNetworkAddress(IPC_HOST, port)) { init(); diff --git a/src/lib/ipc/CIpcServer.h b/src/lib/ipc/CIpcServer.h index af0b4cdc..a10c526c 100644 --- a/src/lib/ipc/CIpcServer.h +++ b/src/lib/ipc/CIpcServer.h @@ -29,6 +29,7 @@ class CEvent; class CIpcClientProxy; class CIpcMessage; class IEventQueue; +class CSocketMultiplexer; //! IPC server for communication between daemon and GUI. /*! @@ -39,8 +40,8 @@ and allows the daemon and client/server to send log data to the GUI. */ class CIpcServer { public: - CIpcServer(IEventQueue* events); - CIpcServer(IEventQueue* events, int port); + CIpcServer(IEventQueue* events, CSocketMultiplexer* socketMultiplexer); + CIpcServer(IEventQueue* events, CSocketMultiplexer* socketMultiplexer, int port); virtual ~CIpcServer(); //! @name manipulators diff --git a/src/lib/net/CSocketMultiplexer.cpp b/src/lib/net/CSocketMultiplexer.cpp index 27ee325e..b57097df 100644 --- a/src/lib/net/CSocketMultiplexer.cpp +++ b/src/lib/net/CSocketMultiplexer.cpp @@ -32,8 +32,6 @@ // CSocketMultiplexer // -CSocketMultiplexer* CSocketMultiplexer::s_instance = NULL; - CSocketMultiplexer::CSocketMultiplexer() : m_mutex(new CMutex), m_thread(NULL), @@ -44,8 +42,6 @@ CSocketMultiplexer::CSocketMultiplexer() : m_jobListLocker(NULL), m_jobListLockLocker(NULL) { - assert(s_instance == NULL); - // this pointer just has to be unique and not NULL. it will // never be dereferenced. it's used to identify cursor nodes // in the jobs list. @@ -54,8 +50,6 @@ CSocketMultiplexer::CSocketMultiplexer() : // start thread m_thread = new CThread(new TMethodJob( this, &CSocketMultiplexer::serviceThread)); - - s_instance = this; } CSocketMultiplexer::~CSocketMultiplexer() @@ -76,15 +70,6 @@ CSocketMultiplexer::~CSocketMultiplexer() i != m_socketJobMap.end(); ++i) { delete *(i->second); } - - s_instance = NULL; -} - -CSocketMultiplexer* -CSocketMultiplexer::getInstance() -{ - assert(s_instance != NULL); - return s_instance; } void diff --git a/src/lib/net/CSocketMultiplexer.h b/src/lib/net/CSocketMultiplexer.h index 5f9b2320..8e10a1a6 100644 --- a/src/lib/net/CSocketMultiplexer.h +++ b/src/lib/net/CSocketMultiplexer.h @@ -108,8 +108,6 @@ private: CSocketJobs m_socketJobs; CSocketJobMap m_socketJobMap; ISocketMultiplexerJob* m_cursorMark; - - static CSocketMultiplexer* s_instance; }; #endif diff --git a/src/lib/net/CTCPListenSocket.cpp b/src/lib/net/CTCPListenSocket.cpp index 6acede19..5d3e1739 100644 --- a/src/lib/net/CTCPListenSocket.cpp +++ b/src/lib/net/CTCPListenSocket.cpp @@ -33,8 +33,9 @@ // CTCPListenSocket // -CTCPListenSocket::CTCPListenSocket(IEventQueue* events) : - m_events(events) +CTCPListenSocket::CTCPListenSocket(IEventQueue* events, CSocketMultiplexer* socketMultiplexer) : + m_events(events), + m_socketMultiplexer(socketMultiplexer) { m_mutex = new CMutex; try { @@ -49,7 +50,7 @@ CTCPListenSocket::~CTCPListenSocket() { try { if (m_socket != NULL) { - CSocketMultiplexer::getInstance()->removeSocket(this); + m_socketMultiplexer->removeSocket(this); ARCH->closeSocket(m_socket); } } @@ -67,7 +68,7 @@ CTCPListenSocket::bind(const CNetworkAddress& addr) ARCH->setReuseAddrOnSocket(m_socket, true); ARCH->bindSocket(m_socket, addr.getAddress()); ARCH->listenOnSocket(m_socket); - CSocketMultiplexer::getInstance()->addSocket(this, + m_socketMultiplexer->addSocket(this, new TSocketMultiplexerMethodJob( this, &CTCPListenSocket::serviceListening, m_socket, true, false)); @@ -88,7 +89,7 @@ CTCPListenSocket::close() throw XIOClosed(); } try { - CSocketMultiplexer::getInstance()->removeSocket(this); + m_socketMultiplexer->removeSocket(this); ARCH->closeSocket(m_socket); m_socket = NULL; } @@ -108,9 +109,9 @@ CTCPListenSocket::accept() { IDataSocket* socket = NULL; try { - socket = new CTCPSocket(m_events, ARCH->acceptSocket(m_socket, NULL)); + socket = new CTCPSocket(m_events, m_socketMultiplexer, ARCH->acceptSocket(m_socket, NULL)); if (socket != NULL) { - CSocketMultiplexer::getInstance()->addSocket(this, + m_socketMultiplexer->addSocket(this, new TSocketMultiplexerMethodJob( this, &CTCPListenSocket::serviceListening, m_socket, true, false)); diff --git a/src/lib/net/CTCPListenSocket.h b/src/lib/net/CTCPListenSocket.h index 580c7491..ceff60bd 100644 --- a/src/lib/net/CTCPListenSocket.h +++ b/src/lib/net/CTCPListenSocket.h @@ -25,6 +25,7 @@ class CMutex; class ISocketMultiplexerJob; class IEventQueue; +class CSocketMultiplexer; //! TCP listen socket /*! @@ -32,7 +33,7 @@ A listen socket using TCP. */ class CTCPListenSocket : public IListenSocket { public: - CTCPListenSocket(IEventQueue* events); + CTCPListenSocket(IEventQueue* events, CSocketMultiplexer* socketMultiplexer); ~CTCPListenSocket(); // ISocket overrides @@ -52,6 +53,7 @@ private: CArchSocket m_socket; CMutex* m_mutex; IEventQueue* m_events; + CSocketMultiplexer* m_socketMultiplexer; }; #endif diff --git a/src/lib/net/CTCPSocket.cpp b/src/lib/net/CTCPSocket.cpp index caaa7836..77db4024 100644 --- a/src/lib/net/CTCPSocket.cpp +++ b/src/lib/net/CTCPSocket.cpp @@ -35,11 +35,12 @@ // CTCPSocket // -CTCPSocket::CTCPSocket(IEventQueue* events) : +CTCPSocket::CTCPSocket(IEventQueue* events, CSocketMultiplexer* socketMultiplexer) : IDataSocket(events), m_events(events), m_mutex(), - m_flushed(&m_mutex, true) + m_flushed(&m_mutex, true), + m_socketMultiplexer(socketMultiplexer) { try { m_socket = ARCH->newSocket(IArchNetwork::kINET, IArchNetwork::kSTREAM); @@ -51,12 +52,13 @@ CTCPSocket::CTCPSocket(IEventQueue* events) : init(); } -CTCPSocket::CTCPSocket(IEventQueue* events, CArchSocket socket) : +CTCPSocket::CTCPSocket(IEventQueue* events, CSocketMultiplexer* socketMultiplexer, CArchSocket socket) : IDataSocket(events), m_events(events), m_mutex(), m_socket(socket), - m_flushed(&m_mutex, true) + m_flushed(&m_mutex, true), + m_socketMultiplexer(socketMultiplexer) { assert(m_socket != NULL); @@ -316,10 +318,10 @@ CTCPSocket::setJob(ISocketMultiplexerJob* job) { // multiplexer will delete the old job if (job == NULL) { - CSocketMultiplexer::getInstance()->removeSocket(this); + m_socketMultiplexer->removeSocket(this); } else { - CSocketMultiplexer::getInstance()->addSocket(this, job); + m_socketMultiplexer->addSocket(this, job); } } diff --git a/src/lib/net/CTCPSocket.h b/src/lib/net/CTCPSocket.h index 2a3645c7..e6da7e47 100644 --- a/src/lib/net/CTCPSocket.h +++ b/src/lib/net/CTCPSocket.h @@ -29,6 +29,7 @@ class CMutex; class CThread; class ISocketMultiplexerJob; class IEventQueue; +class CSocketMultiplexer; //! TCP data socket /*! @@ -36,8 +37,8 @@ A data socket using TCP. */ class CTCPSocket : public IDataSocket { public: - CTCPSocket(IEventQueue* events); - CTCPSocket(IEventQueue* events, CArchSocket socket); + CTCPSocket(IEventQueue* events, CSocketMultiplexer* socketMultiplexer); + CTCPSocket(IEventQueue* events, CSocketMultiplexer* socketMultiplexer, CArchSocket socket); ~CTCPSocket(); // ISocket overrides @@ -87,6 +88,7 @@ private: bool m_readable; bool m_writable; IEventQueue* m_events; + CSocketMultiplexer* m_socketMultiplexer; }; #endif diff --git a/src/lib/net/CTCPSocketFactory.cpp b/src/lib/net/CTCPSocketFactory.cpp index 33cdc0ca..cbe3ed0f 100644 --- a/src/lib/net/CTCPSocketFactory.cpp +++ b/src/lib/net/CTCPSocketFactory.cpp @@ -24,8 +24,9 @@ // CTCPSocketFactory // -CTCPSocketFactory::CTCPSocketFactory(IEventQueue* events) : - m_events(events) +CTCPSocketFactory::CTCPSocketFactory(IEventQueue* events, CSocketMultiplexer* socketMultiplexer) : + m_events(events), + m_socketMultiplexer(socketMultiplexer) { // do nothing } @@ -38,11 +39,11 @@ CTCPSocketFactory::~CTCPSocketFactory() IDataSocket* CTCPSocketFactory::create() const { - return new CTCPSocket(m_events); + return new CTCPSocket(m_events, m_socketMultiplexer); } IListenSocket* CTCPSocketFactory::createListen() const { - return new CTCPListenSocket(m_events); + return new CTCPListenSocket(m_events, m_socketMultiplexer); } diff --git a/src/lib/net/CTCPSocketFactory.h b/src/lib/net/CTCPSocketFactory.h index df41f2c8..872bf2df 100644 --- a/src/lib/net/CTCPSocketFactory.h +++ b/src/lib/net/CTCPSocketFactory.h @@ -22,11 +22,12 @@ #include "ISocketFactory.h" class IEventQueue; +class CSocketMultiplexer; //! Socket factory for TCP sockets class CTCPSocketFactory : public ISocketFactory { public: - CTCPSocketFactory(IEventQueue* events); + CTCPSocketFactory(IEventQueue* events, CSocketMultiplexer* socketMultiplexer); virtual ~CTCPSocketFactory(); // ISocketFactory overrides @@ -35,6 +36,7 @@ public: private: IEventQueue* m_events; + CSocketMultiplexer* m_socketMultiplexer; }; #endif diff --git a/src/lib/server/CBaseClientProxy.h b/src/lib/server/CBaseClientProxy.h index 42441e56..03502fb5 100644 --- a/src/lib/server/CBaseClientProxy.h +++ b/src/lib/server/CBaseClientProxy.h @@ -83,6 +83,7 @@ public: virtual void screensaver(bool activate) = 0; virtual void resetOptions() = 0; virtual void setOptions(const COptionsList& options) = 0; + virtual void fileChunkSending(UInt8 mark, const UInt8* data) = 0; virtual CString getName() const; private: diff --git a/src/lib/server/CClientListener.h b/src/lib/server/CClientListener.h index c824bbc6..9f72e172 100644 --- a/src/lib/server/CClientListener.h +++ b/src/lib/server/CClientListener.h @@ -48,7 +48,7 @@ public: //! @name manipulators //@{ - void setServer(CServer* server); + void setServer(CServer* server); //@} @@ -63,6 +63,9 @@ public: */ CClientProxy* getNextClient(); + //! Get server which owns this listener + CServer* getServer() { return m_server; } + //@} private: diff --git a/src/lib/server/CClientProxy.h b/src/lib/server/CClientProxy.h index 9225195a..4cebabc2 100644 --- a/src/lib/server/CClientProxy.h +++ b/src/lib/server/CClientProxy.h @@ -89,6 +89,7 @@ public: virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2) = 0; virtual void gameDeviceTimingReq() = 0; virtual void cryptoIv(const UInt8* iv) = 0; + virtual void fileChunkSending(UInt8 mark, const UInt8* data) = 0; private: synergy::IStream* m_stream; diff --git a/src/lib/server/CClientProxy1_0.cpp b/src/lib/server/CClientProxy1_0.cpp index d5add895..319fd6ce 100644 --- a/src/lib/server/CClientProxy1_0.cpp +++ b/src/lib/server/CClientProxy1_0.cpp @@ -393,6 +393,13 @@ CClientProxy1_0::cryptoIv(const UInt8* iv) LOG((CLOG_DEBUG "cryptoIv not supported")); } +void +CClientProxy1_0::fileChunkSending(UInt8 mark, const UInt8* iv) +{ + // ignore -- not supported in protocol 1.0 + LOG((CLOG_DEBUG "fileChunkSending not supported")); +} + void CClientProxy1_0::screensaver(bool on) { diff --git a/src/lib/server/CClientProxy1_0.h b/src/lib/server/CClientProxy1_0.h index 31f51e85..62e46a46 100644 --- a/src/lib/server/CClientProxy1_0.h +++ b/src/lib/server/CClientProxy1_0.h @@ -64,6 +64,7 @@ public: virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2); virtual void gameDeviceTimingReq(); virtual void cryptoIv(const UInt8* iv); + virtual void fileChunkSending(UInt8 mark, const UInt8* data); protected: virtual bool parseHandshakeMessage(const UInt8* code); diff --git a/src/lib/server/CClientProxy1_5.cpp b/src/lib/server/CClientProxy1_5.cpp new file mode 100644 index 00000000..0f1fdeb1 --- /dev/null +++ b/src/lib/server/CClientProxy1_5.cpp @@ -0,0 +1,56 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2013 Bolton Software 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 "CClientProxy1_5.h" +#include "CProtocolUtil.h" +#include "CLog.h" +#include "IStream.h" + +// +// CClientProxy1_5 +// + +CClientProxy1_5::CClientProxy1_5(const CString& name, synergy::IStream* stream, CServer* server, IEventQueue* events) : + CClientProxy1_4(name, stream, server, events) +{ +} + +CClientProxy1_5::~CClientProxy1_5() +{ +} + +void +CClientProxy1_5::fileChunkSending(UInt8 mark, const UInt8* data) +{ + CString chunk(reinterpret_cast(data)); + + switch (mark) { + case '0': + LOG((CLOG_DEBUG2 "file sending start: file size = %s", data)); + break; + + case '1': + LOG((CLOG_DEBUG2 "file chunk sending: %s", data)); + break; + + case '2': + LOG((CLOG_DEBUG2 "file sending finished")); + break; + } + + CProtocolUtil::writef(getStream(), kMsgDFileTransfer, mark, &chunk); +} diff --git a/src/lib/server/CClientProxy1_5.h b/src/lib/server/CClientProxy1_5.h new file mode 100644 index 00000000..e88d91c3 --- /dev/null +++ b/src/lib/server/CClientProxy1_5.h @@ -0,0 +1,32 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2013 Bolton Software 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 "CClientProxy1_4.h" + +class CServer; +class IEventQueue; + +//! Proxy for client implementing protocol version 1.5 +class CClientProxy1_5 : public CClientProxy1_4 { +public: + CClientProxy1_5(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events); + ~CClientProxy1_5(); + + virtual void fileChunkSending(UInt8 mark, const UInt8* data); +}; diff --git a/src/lib/server/CClientProxyUnknown.cpp b/src/lib/server/CClientProxyUnknown.cpp index a35179b1..4dc62330 100644 --- a/src/lib/server/CClientProxyUnknown.cpp +++ b/src/lib/server/CClientProxyUnknown.cpp @@ -22,6 +22,7 @@ #include "CClientProxy1_2.h" #include "CClientProxy1_3.h" #include "CClientProxy1_4.h" +#include "CClientProxy1_5.h" #include "ProtocolTypes.h" #include "CProtocolUtil.h" #include "XSynergy.h" @@ -221,6 +222,10 @@ CClientProxyUnknown::handleData(const CEvent&, void*) case 4: m_proxy = new CClientProxy1_4(name, m_stream, m_server, m_events); break; + + case 5: + m_proxy = new CClientProxy1_5(name, m_stream, m_server, m_events); + break; } } diff --git a/src/lib/server/CConfig.h b/src/lib/server/CConfig.h index 9d196147..5f6685ad 100644 --- a/src/lib/server/CConfig.h +++ b/src/lib/server/CConfig.h @@ -176,6 +176,10 @@ public: CConfig(IEventQueue* events); virtual ~CConfig(); +#ifdef TEST_ENV + CConfig() : m_inputFilter(NULL) { } +#endif + //! @name manipulators //@{ @@ -313,7 +317,8 @@ public: Returns the hot key input filter. Clients can modify hotkeys using that object. */ - CInputFilter* getInputFilter(); + virtual CInputFilter* + getInputFilter(); //@} //! @name accessors @@ -339,7 +344,7 @@ public: /*! Returns true iff \c name names a screen. */ - bool isScreen(const CString& name) const; + virtual bool isScreen(const CString& name) const; //! Test for canonical screen name /*! diff --git a/src/lib/server/CInputFilter.h b/src/lib/server/CInputFilter.h index 6e1fa76f..4f9a781c 100644 --- a/src/lib/server/CInputFilter.h +++ b/src/lib/server/CInputFilter.h @@ -321,6 +321,10 @@ public: CInputFilter(const CInputFilter&); virtual ~CInputFilter(); +#ifdef TEST_ENV + CInputFilter() : m_primaryClient(NULL) { } +#endif + CInputFilter& operator=(const CInputFilter&); // add rule, adopting the condition and the actions @@ -334,7 +338,7 @@ public: // enable event filtering using the given primary client. disable // if client is NULL. - void setPrimaryClient(CPrimaryClient* client); + virtual void setPrimaryClient(CPrimaryClient* client); // convert rules to a string CString format(const CString& linePrefix) const; diff --git a/src/lib/server/CMakeLists.txt b/src/lib/server/CMakeLists.txt index 3c2b0582..6affb1a1 100644 --- a/src/lib/server/CMakeLists.txt +++ b/src/lib/server/CMakeLists.txt @@ -23,6 +23,7 @@ set(inc CClientProxy1_2.h CClientProxy1_3.h CClientProxy1_4.h + CClientProxy1_5.h CClientProxyUnknown.h CConfig.h CInputFilter.h @@ -39,6 +40,7 @@ set(src CClientProxy1_2.cpp CClientProxy1_3.cpp CClientProxy1_4.cpp + CClientProxy1_5.cpp CClientProxyUnknown.cpp CConfig.cpp CInputFilter.cpp diff --git a/src/lib/server/CPrimaryClient.cpp b/src/lib/server/CPrimaryClient.cpp index 410d88a2..c010d48d 100644 --- a/src/lib/server/CPrimaryClient.cpp +++ b/src/lib/server/CPrimaryClient.cpp @@ -28,7 +28,8 @@ CPrimaryClient::CPrimaryClient(const CString& name, CScreen* screen) : CBaseClientProxy(name), m_screen(screen), - m_fakeInputCount(0) + m_fakeInputCount(0), + m_mock(false) { // all clipboards are clean for (UInt32 i = 0; i < kClipboardEnd; ++i) { @@ -272,6 +273,12 @@ CPrimaryClient::screensaver(bool) // ignore } +void +CPrimaryClient::fileChunkSending(UInt8 mark, const UInt8* data) +{ + // ignore +} + void CPrimaryClient::resetOptions() { diff --git a/src/lib/server/CPrimaryClient.h b/src/lib/server/CPrimaryClient.h index 30ede0df..a2a0f6b2 100644 --- a/src/lib/server/CPrimaryClient.h +++ b/src/lib/server/CPrimaryClient.h @@ -38,6 +38,10 @@ public: CPrimaryClient(const CString& name, CScreen* screen); ~CPrimaryClient(); +#ifdef TEST_ENV + CPrimaryClient() : CBaseClientProxy(""), m_mock(true) { } +#endif + //! @name manipulators //@{ @@ -45,20 +49,20 @@ public: /*! Handles reconfiguration of jump zones. */ - void reconfigure(UInt32 activeSides); + virtual void reconfigure(UInt32 activeSides); //! Register a system hotkey /*! Registers a system-wide hotkey for key \p key with modifiers \p mask. Returns an id used to unregister the hotkey. */ - UInt32 registerHotKey(KeyID key, KeyModifierMask mask); + virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); //! Unregister a system hotkey /*! Unregisters a previously registered hot key. */ - void unregisterHotKey(UInt32 id); + virtual void unregisterHotKey(UInt32 id); //! Prepare to synthesize input on primary screen /*! @@ -98,7 +102,8 @@ public: /*! Returns the primary screen's current toggle modifier key state. */ - KeyModifierMask getToggleMask() const; + virtual KeyModifierMask + getToggleMask() const; //! Get screen lock state /*! @@ -143,11 +148,13 @@ public: virtual void screensaver(bool activate); virtual void resetOptions(); virtual void setOptions(const COptionsList& options); + virtual void fileChunkSending(UInt8 mark, const UInt8* data); private: CScreen* m_screen; bool m_clipboardDirty[kClipboardEnd]; SInt32 m_fakeInputCount; + bool m_mock; }; #endif diff --git a/src/lib/server/CServer.cpp b/src/lib/server/CServer.cpp index 09c07aee..320a69a3 100644 --- a/src/lib/server/CServer.cpp +++ b/src/lib/server/CServer.cpp @@ -41,7 +41,7 @@ // CServer // -CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient, CScreen* screen, IEventQueue* events) : +CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen, IEventQueue* events) : m_events(events), m_mock(false), m_primaryClient(primaryClient), @@ -51,8 +51,8 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient, CScreen* m_yDelta(0), m_xDelta2(0), m_yDelta2(0), - m_config(events), - m_inputFilter(m_config.getInputFilter()), + m_config(&config), + m_inputFilter(config.getInputFilter()), m_activeSaver(NULL), m_switchDir(kNoDirection), m_switchScreen(NULL), @@ -173,6 +173,10 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient, CScreen* m_inputFilter, new TMethodEventJob(this, &CServer::handleFakeInputEndEvent)); + m_events->adoptHandler(m_events->forIScreen().fileChunkSending(), + this, + new TMethodEventJob(this, + &CServer::handleFileChunkSendingEvent)); // add connection addClient(m_primaryClient); @@ -185,8 +189,8 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient, CScreen* m_inputFilter->setPrimaryClient(m_primaryClient); // Determine if scroll lock is already set. If so, lock the cursor to the primary screen - int keyValue = m_primaryClient->getToggleMask (); - if (m_primaryClient->getToggleMask () & KeyModifierScrollLock) { + int keyValue = m_primaryClient->getToggleMask(); + if (m_primaryClient->getToggleMask() & KeyModifierScrollLock) { LOG((CLOG_DEBUG "scroll lock on initially. locked to screen")); m_lockedToScreen = true; } @@ -259,7 +263,6 @@ CServer::setConfig(const CConfig& config) closeClients(config); // cut over - m_config = config; processOptions(); // add ScrollLock as a hotkey to lock to the screen. this was a @@ -269,7 +272,7 @@ CServer::setConfig(const CConfig& config) // we will unfortunately generate a warning. if the user has // configured a CLockCursorToScreenAction then we don't add // ScrollLock as a hotkey. - if (!m_config.hasLockToScreenAction()) { + if (!m_config->hasLockToScreenAction()) { IPlatformScreen::CKeyInfo* key = IPlatformScreen::CKeyInfo::alloc(kKeyScrollLock, 0, 0, 0); CInputFilter::CRule rule(new CInputFilter::CKeystrokeCondition(m_events, key)); @@ -301,7 +304,7 @@ CServer::adoptClient(CBaseClientProxy* client) &CServer::handleClientDisconnected, client)); // name must be in our configuration - if (!m_config.isScreen(client->getName())) { + if (!m_config->isScreen(client->getName())) { LOG((CLOG_WARN "unrecognised client name \"%s\", check server config", client->getName().c_str())); closeClient(client, kMsgEUnknown); return; @@ -375,7 +378,7 @@ CServer::getClients(std::vector& list) const CString CServer::getName(const CBaseClientProxy* client) const { - CString name = m_config.getCanonicalName(client->getName()); + CString name = m_config->getCanonicalName(client->getName()); if (name.empty()) { name = client->getName(); } @@ -579,7 +582,7 @@ CServer::hasAnyNeighbor(CBaseClientProxy* client, EDirection dir) const { assert(client != NULL); - return m_config.hasNeighbor(getName(client), dir); + return m_config->hasNeighbor(getName(client), dir); } CBaseClientProxy* @@ -601,7 +604,7 @@ CServer::getNeighbor(CBaseClientProxy* src, // search for the closest neighbor that exists in direction dir float tTmp; for (;;) { - CString dstName(m_config.getNeighbor(srcName, dir, t, &tTmp)); + CString dstName(m_config->getNeighbor(srcName, dir, t, &tTmp)); // if nothing in that direction then return NULL. if the // destination is the source then we can make no more @@ -757,25 +760,25 @@ CServer::avoidJumpZone(CBaseClientProxy* dst, // don't need to move inwards because that side can't provoke a jump. switch (dir) { case kLeft: - if (!m_config.getNeighbor(dstName, kRight, t, NULL).empty() && + if (!m_config->getNeighbor(dstName, kRight, t, NULL).empty() && x > dx + dw - 1 - z) x = dx + dw - 1 - z; break; case kRight: - if (!m_config.getNeighbor(dstName, kLeft, t, NULL).empty() && + if (!m_config->getNeighbor(dstName, kLeft, t, NULL).empty() && x < dx + z) x = dx + z; break; case kTop: - if (!m_config.getNeighbor(dstName, kBottom, t, NULL).empty() && + if (!m_config->getNeighbor(dstName, kBottom, t, NULL).empty() && y > dy + dh - 1 - z) y = dy + dh - 1 - z; break; case kBottom: - if (!m_config.getNeighbor(dstName, kTop, t, NULL).empty() && + if (!m_config->getNeighbor(dstName, kTop, t, NULL).empty() && y < dy + z) y = dy + z; break; @@ -839,9 +842,9 @@ CServer::isSwitchOkay(CBaseClientProxy* newScreen, // are we in a locked corner? first check if screen has the option set // and, if not, check the global options. const CConfig::CScreenOptions* options = - m_config.getOptions(getName(m_active)); + m_config->getOptions(getName(m_active)); if (options == NULL || options->count(kOptionScreenSwitchCorners) == 0) { - options = m_config.getOptions(""); + options = m_config->getOptions(""); } if (options != NULL && options->count(kOptionScreenSwitchCorners) > 0) { // get corner mask and size @@ -1089,7 +1092,7 @@ CServer::sendOptions(CBaseClientProxy* client) const // look up options for client const CConfig::CScreenOptions* options = - m_config.getOptions(getName(client)); + m_config->getOptions(getName(client)); if (options != NULL) { // convert options to a more convenient form for sending optionsList.reserve(2 * options->size()); @@ -1101,7 +1104,7 @@ CServer::sendOptions(CBaseClientProxy* client) const } // look up global options - options = m_config.getOptions(""); + options = m_config->getOptions(""); if (options != NULL) { // convert options to a more convenient form for sending optionsList.reserve(optionsList.size() + 2 * options->size()); @@ -1120,7 +1123,7 @@ CServer::sendOptions(CBaseClientProxy* client) const void CServer::processOptions() { - const CConfig::CScreenOptions* options = m_config.getOptions(""); + const CConfig::CScreenOptions* options = m_config->getOptions(""); if (options == NULL) { return; } @@ -1510,6 +1513,13 @@ CServer::handleFakeInputEndEvent(const CEvent&, void*) m_primaryClient->fakeInputEnd(); } +void +CServer::handleFileChunkSendingEvent(const CEvent& event, void*) +{ + UInt8* data = reinterpret_cast(event.getData()); + onFileChunkSending(data); +} + void CServer::onClipboardChanged(CBaseClientProxy* sender, ClipboardID id, UInt32 seqNum) @@ -1970,6 +1980,16 @@ CServer::onGameDeviceTimingReq() m_active->gameDeviceTimingReq(); } +void +CServer::onFileChunkSending(const UInt8* data) +{ + LOG((CLOG_DEBUG1 "onFileChunkSending")); + assert(m_active != NULL); + + // relay + m_active->fileChunkSending(data[0], &data[1]); +} + bool CServer::addClient(CBaseClientProxy* client) { diff --git a/src/lib/server/CServer.h b/src/lib/server/CServer.h index 466ec5b8..91258924 100644 --- a/src/lib/server/CServer.h +++ b/src/lib/server/CServer.h @@ -43,7 +43,7 @@ class IEventQueue; /*! This class implements the top-level server algorithms for synergy. */ -class CServer : public INode { +class CServer : public INode { public: //! Lock cursor to screen data class CLockCursorToScreenInfo { @@ -103,11 +103,12 @@ public: client (local screen) \p primaryClient. The client retains ownership of \p primaryClient. */ - CServer(const CConfig& config, CPrimaryClient* primaryClient, CScreen* screen, IEventQueue* events); + CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen, IEventQueue* events); ~CServer(); - + #ifdef TEST_ENV - CServer() : m_mock(true), m_events(NULL), m_config(NULL) { } + CServer() : m_mock(true), m_config(NULL) { } + void setActive(CBaseClientProxy* active) { m_active = active; } #endif //! @name manipulators @@ -297,6 +298,7 @@ private: void handleLockCursorToScreenEvent(const CEvent&, void*); void handleFakeInputBeginEvent(const CEvent&, void*); void handleFakeInputEndEvent(const CEvent&, void*); + void handleFileChunkSendingEvent(const CEvent&, void*); // event processing void onClipboardChanged(CBaseClientProxy* sender, @@ -316,6 +318,7 @@ private: void onGameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2); void onGameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2); void onGameDeviceTimingReq(); + void onFileChunkSending(const UInt8* data); // add client to list and attach event handlers for client bool addClient(CBaseClientProxy*); @@ -386,7 +389,7 @@ private: SInt32 m_xDelta2, m_yDelta2; // current configuration - CConfig m_config; + CConfig* m_config; // input filter (from m_config); CInputFilter* m_inputFilter; diff --git a/src/lib/synergy/CApp.cpp b/src/lib/synergy/CApp.cpp index 3c5a28ba..a8f3cc8e 100644 --- a/src/lib/synergy/CApp.cpp +++ b/src/lib/synergy/CApp.cpp @@ -357,7 +357,7 @@ CApp::initApp(int argc, const char** argv) void CApp::initIpcClient() { - m_ipcClient = new CIpcClient(m_events); + m_ipcClient = new CIpcClient(m_events, m_socketMultiplexer); m_ipcClient->connect(); m_events->adoptHandler( diff --git a/src/lib/synergy/CApp.h b/src/lib/synergy/CApp.h index 31bd0a46..e335ecf3 100644 --- a/src/lib/synergy/CApp.h +++ b/src/lib/synergy/CApp.h @@ -35,6 +35,7 @@ class ILogOutputter; class CFileLogOutputter; class CScreen; class IEventQueue; +class CSocketMultiplexer; typedef IArchTaskBarReceiver* (*CreateTaskBarReceiverFunc)(const CBufferedLogOutputter*, IEventQueue* events); @@ -95,7 +96,10 @@ public: virtual void setByeFunc(void(*bye)(int)) { m_bye = bye; } virtual void bye(int error) { m_bye(error); } - virtual IEventQueue* getEvents() const { return m_events; } + virtual IEventQueue* getEvents() const { return m_events; } + + void setSocketMultiplexer(CSocketMultiplexer* sm) { m_socketMultiplexer = sm; } + CSocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; } private: void handleIpcMessage(const CEvent&, void*); @@ -117,6 +121,7 @@ private: ARCH_APP_UTIL m_appUtil; CIpcClient* m_ipcClient; IEventQueue* m_events; + CSocketMultiplexer* m_socketMultiplexer; }; #define BYE "\nTry `%s --help' for more information." diff --git a/src/lib/synergy/CClientApp.cpp b/src/lib/synergy/CClientApp.cpp index 1e3976ce..e0107dc0 100644 --- a/src/lib/synergy/CClientApp.cpp +++ b/src/lib/synergy/CClientApp.cpp @@ -391,7 +391,13 @@ CClient* CClientApp::openClient(const CString& name, const CNetworkAddress& address, CScreen* screen, const CCryptoOptions& crypto) { CClient* client = new CClient( - m_events, name, address, new CTCPSocketFactory(m_events), NULL, screen, crypto); + m_events, + name, + address, + new CTCPSocketFactory(m_events, getSocketMultiplexer()), + NULL, + screen, + crypto); try { m_events->adoptHandler( @@ -522,6 +528,7 @@ CClientApp::mainLoop() // create socket multiplexer. this must happen after daemonization // on unix because threads evaporate across a fork(). CSocketMultiplexer multiplexer; + setSocketMultiplexer(&multiplexer); // start client, etc appUtil().startNode(); diff --git a/src/lib/synergy/CDaemonApp.cpp b/src/lib/synergy/CDaemonApp.cpp index af85a086..c219aece 100644 --- a/src/lib/synergy/CDaemonApp.cpp +++ b/src/lib/synergy/CDaemonApp.cpp @@ -203,7 +203,7 @@ CDaemonApp::mainLoop(bool logToFile) CSocketMultiplexer multiplexer; // uses event queue, must be created here. - m_ipcServer = new CIpcServer(m_events); + m_ipcServer = new CIpcServer(m_events, &multiplexer); // send logging to gui via ipc, log system adopts outputter. m_ipcLogOutputter = new CIpcLogOutputter(*m_ipcServer); diff --git a/src/lib/synergy/CScreen.cpp b/src/lib/synergy/CScreen.cpp index 0ffa4de5..34f81a1d 100644 --- a/src/lib/synergy/CScreen.cpp +++ b/src/lib/synergy/CScreen.cpp @@ -35,7 +35,8 @@ CScreen::CScreen(IPlatformScreen* platformScreen, IEventQueue* events) : m_enabled(false), m_entered(m_isPrimary), m_screenSaverSync(true), - m_fakeInput(false) + m_fakeInput(false), + m_mock(false) { assert(m_screen != NULL); @@ -47,6 +48,10 @@ CScreen::CScreen(IPlatformScreen* platformScreen, IEventQueue* events) : CScreen::~CScreen() { + if (m_mock) { + return; + } + if (m_enabled) { disable(); } diff --git a/src/lib/synergy/CScreen.h b/src/lib/synergy/CScreen.h index 08434e59..915e5572 100644 --- a/src/lib/synergy/CScreen.h +++ b/src/lib/synergy/CScreen.h @@ -40,6 +40,10 @@ public: CScreen(IPlatformScreen* platformScreen, IEventQueue* events); virtual ~CScreen(); +#ifdef TEST_ENV + CScreen() : m_mock(true) { } +#endif + //! @name manipulators //@{ @@ -49,14 +53,14 @@ public: For a secondary screen it also means disabling the screen saver if synchronizing it and preparing to synthesize events. */ - void enable(); + virtual void enable(); //! Deactivate screen /*! Undoes the operations in activate() and events are no longer reported. It also releases keys that are logically pressed. */ - void disable(); + virtual void disable(); //! Enter screen /*! @@ -208,14 +212,14 @@ public: /*! Resets all options to their default values. */ - void resetOptions(); + virtual void resetOptions(); //! Notify of options changes /*! Set options to given values. Ignores unknown options and doesn't modify options that aren't given in \c options. */ - void setOptions(const COptionsList& options); + virtual void setOptions(const COptionsList& options); //! Set clipboard sequence number /*! @@ -343,6 +347,8 @@ private: bool m_fakeInput; IEventQueue* m_events; + + bool m_mock; }; #endif diff --git a/src/lib/synergy/CServerApp.cpp b/src/lib/synergy/CServerApp.cpp index 7df21b5e..239dd946 100644 --- a/src/lib/synergy/CServerApp.cpp +++ b/src/lib/synergy/CServerApp.cpp @@ -670,8 +670,11 @@ CClientListener* CServerApp::openClientListener(const CNetworkAddress& address) { CClientListener* listen = new CClientListener( - address, new CTCPSocketFactory(m_events), - NULL, args().m_crypto, m_events); + address, + new CTCPSocketFactory(m_events, getSocketMultiplexer()), + NULL, + args().m_crypto, + m_events); m_events->adoptHandler( m_events->forCClientListener().connected(), listen, @@ -682,7 +685,7 @@ CServerApp::openClientListener(const CNetworkAddress& address) } CServer* -CServerApp::openServer(const CConfig& config, CPrimaryClient* primaryClient) +CServerApp::openServer(CConfig& config, CPrimaryClient* primaryClient) { CServer* server = new CServer(config, primaryClient, s_serverScreen, m_events); @@ -720,6 +723,7 @@ CServerApp::mainLoop() // create socket multiplexer. this must happen after daemonization // on unix because threads evaporate across a fork(). CSocketMultiplexer multiplexer; + setSocketMultiplexer(&multiplexer); // if configuration has no screens then add this system // as the default diff --git a/src/lib/synergy/CServerApp.h b/src/lib/synergy/CServerApp.h index 0bf3e715..8c3acf51 100644 --- a/src/lib/synergy/CServerApp.h +++ b/src/lib/synergy/CServerApp.h @@ -100,7 +100,7 @@ public: void handleSuspend(const CEvent&, void*); void handleResume(const CEvent&, void*); CClientListener* openClientListener(const CNetworkAddress& address); - CServer* openServer(const CConfig& config, CPrimaryClient* primaryClient); + CServer* openServer(CConfig& config, CPrimaryClient* primaryClient); void handleNoClients(const CEvent&, void*); bool startServer(); int mainLoop(); diff --git a/src/lib/synergy/INode.h b/src/lib/synergy/INode.h index 2ab170ef..53432740 100644 --- a/src/lib/synergy/INode.h +++ b/src/lib/synergy/INode.h @@ -16,6 +16,8 @@ * along with this program. If not, see . */ +#pragma once + #include "IInterface.h" class INode : IInterface { diff --git a/src/lib/synergy/ProtocolTypes.cpp b/src/lib/synergy/ProtocolTypes.cpp index 35940f39..6eb6e9f7 100644 --- a/src/lib/synergy/ProtocolTypes.cpp +++ b/src/lib/synergy/ProtocolTypes.cpp @@ -51,6 +51,7 @@ const char* kMsgDGameSticks = "DGST%1i%2i%2i%2i%2i"; const char* kMsgDGameTriggers = "DGTR%1i%1i%1i"; const char* kMsgDGameFeedback = "DGFB%1i%2i%2i"; const char* kMsgDCryptoIv = "DCIV%s"; +const char* kMsgDFileTransfer = "DFTR%1i%s"; const char* kMsgQInfo = "QINF"; const char* kMsgEIncompatible = "EICV%2i%2i"; const char* kMsgEBusy = "EBSY"; diff --git a/src/lib/synergy/ProtocolTypes.h b/src/lib/synergy/ProtocolTypes.h index 3ab3a44d..bff4b701 100644 --- a/src/lib/synergy/ProtocolTypes.h +++ b/src/lib/synergy/ProtocolTypes.h @@ -29,7 +29,7 @@ // adds horizontal mouse scrolling // 1.4: adds game device support static const SInt16 kProtocolMajorVersion = 1; -static const SInt16 kProtocolMinorVersion = 4; +static const SInt16 kProtocolMinorVersion = 5; // default contact port number static const UInt16 kDefaultPort = 24800; @@ -288,6 +288,13 @@ extern const char* kMsgDSetOptions; // cryptography stream. extern const char* kMsgDCryptoIv; +// file data: primary <-> secondary +// transfer file data. A mark is used in the first byte. +// 0 means the content followed is the file size. +// 1 means the content followed is the chunk data. +// 2 means the file transfer is finished. +extern const char* kMsgDFileTransfer; + // // query codes // diff --git a/src/test/integtests/CIpcTests.cpp b/src/test/integtests/CIpcTests.cpp index 0ab4f8b3..4c486883 100644 --- a/src/test/integtests/CIpcTests.cpp +++ b/src/test/integtests/CIpcTests.cpp @@ -35,7 +35,7 @@ #include "CString.h" #include "CIpcServerProxy.h" #include "CIpcMessage.h" -#include "CSimpleEventQueueBuffer.h" +#include "CTestEventQueue.h" #define TEST_IPC_PORT 24802 @@ -49,18 +49,9 @@ public: void sendMessageToServer_serverHandleMessageReceived(const CEvent&, void*); void sendMessageToClient_serverHandleClientConnected(const CEvent&, void*); void sendMessageToClient_clientHandleMessageReceived(const CEvent&, void*); - void handleQuitTimeout(const CEvent&, void* vclient); - void raiseQuitEvent(); - void initQuitTimeout(double timeout); - void cleanupQuitTimeout(); - -private: - void timeoutThread(void*); public: CSocketMultiplexer m_multiplexer; - CEventQueue m_events; - CEventQueueTimer* m_quitTimeoutTimer; bool m_connectToServer_helloMessageReceived; bool m_connectToServer_hasClientNode; CIpcServer* m_connectToServer_server; @@ -68,12 +59,14 @@ public: CString m_sendMessageToClient_receivedString; CIpcClient* m_sendMessageToServer_client; CIpcServer* m_sendMessageToClient_server; + CTestEventQueue m_events; }; TEST_F(CIpcTests, connectToServer) { - CIpcServer server(&m_events, TEST_IPC_PORT); + CSocketMultiplexer socketMultiplexer; + CIpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); server.listen(); m_connectToServer_server = &server; @@ -82,13 +75,13 @@ TEST_F(CIpcTests, connectToServer) new TMethodEventJob( this, &CIpcTests::connectToServer_handleMessageReceived)); - CIpcClient client(&m_events, TEST_IPC_PORT); + CIpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); client.connect(); - initQuitTimeout(5); + m_events.initQuitTimeout(5); m_events.loop(); m_events.removeHandler(m_events.forCIpcServer().messageReceived(), &server); - cleanupQuitTimeout(); + m_events.cleanupQuitTimeout(); EXPECT_EQ(true, m_connectToServer_helloMessageReceived); EXPECT_EQ(true, m_connectToServer_hasClientNode); @@ -96,7 +89,8 @@ TEST_F(CIpcTests, connectToServer) TEST_F(CIpcTests, sendMessageToServer) { - CIpcServer server(&m_events, TEST_IPC_PORT); + CSocketMultiplexer socketMultiplexer; + CIpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); server.listen(); // event handler sends "test" command to server. @@ -105,21 +99,22 @@ TEST_F(CIpcTests, sendMessageToServer) new TMethodEventJob( this, &CIpcTests::sendMessageToServer_serverHandleMessageReceived)); - CIpcClient client(&m_events, TEST_IPC_PORT); + CIpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); client.connect(); m_sendMessageToServer_client = &client; - initQuitTimeout(5); + m_events.initQuitTimeout(5); m_events.loop(); m_events.removeHandler(m_events.forCIpcServer().messageReceived(), &server); - cleanupQuitTimeout(); + m_events.cleanupQuitTimeout(); EXPECT_EQ("test", m_sendMessageToServer_receivedString); } TEST_F(CIpcTests, sendMessageToClient) { - CIpcServer server(&m_events, TEST_IPC_PORT); + CSocketMultiplexer socketMultiplexer; + CIpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); server.listen(); m_sendMessageToClient_server = &server; @@ -129,7 +124,7 @@ TEST_F(CIpcTests, sendMessageToClient) new TMethodEventJob( this, &CIpcTests::sendMessageToClient_serverHandleClientConnected)); - CIpcClient client(&m_events, TEST_IPC_PORT); + CIpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); client.connect(); m_events.adoptHandler( @@ -137,17 +132,16 @@ TEST_F(CIpcTests, sendMessageToClient) new TMethodEventJob( this, &CIpcTests::sendMessageToClient_clientHandleMessageReceived)); - initQuitTimeout(5); + m_events.initQuitTimeout(5); m_events.loop(); m_events.removeHandler(m_events.forCIpcServer().messageReceived(), &server); m_events.removeHandler(m_events.forCIpcClient().messageReceived(), &client); - cleanupQuitTimeout(); + m_events.cleanupQuitTimeout(); EXPECT_EQ("test", m_sendMessageToClient_receivedString); } CIpcTests::CIpcTests() : -m_quitTimeoutTimer(nullptr), m_connectToServer_helloMessageReceived(false), m_connectToServer_hasClientNode(false), m_connectToServer_server(nullptr), @@ -168,7 +162,7 @@ CIpcTests::connectToServer_handleMessageReceived(const CEvent& e, void*) m_connectToServer_hasClientNode = m_connectToServer_server->hasClients(kIpcClientNode); m_connectToServer_helloMessageReceived = true; - raiseQuitEvent(); + m_events.raiseQuitEvent(); } } @@ -185,7 +179,7 @@ CIpcTests::sendMessageToServer_serverHandleMessageReceived(const CEvent& e, void CIpcCommandMessage* cm = static_cast(m); LOG((CLOG_DEBUG "got ipc command message, %d", cm->command().c_str())); m_sendMessageToServer_receivedString = cm->command(); - raiseQuitEvent(); + m_events.raiseQuitEvent(); } } @@ -208,37 +202,6 @@ CIpcTests::sendMessageToClient_clientHandleMessageReceived(const CEvent& e, void CIpcLogLineMessage* llm = static_cast(m); LOG((CLOG_DEBUG "got ipc log message, %d", llm->logLine().c_str())); m_sendMessageToClient_receivedString = llm->logLine(); - raiseQuitEvent(); + m_events.raiseQuitEvent(); } } - -void -CIpcTests::raiseQuitEvent() -{ - m_events.addEvent(CEvent(CEvent::kQuit)); -} - -void -CIpcTests::initQuitTimeout(double timeout) -{ - assert(m_quitTimeoutTimer == nullptr); - m_quitTimeoutTimer = m_events.newOneShotTimer(timeout, NULL); - m_events.adoptHandler(CEvent::kTimer, m_quitTimeoutTimer, - new TMethodEventJob( - this, &CIpcTests::handleQuitTimeout)); -} - -void -CIpcTests::cleanupQuitTimeout() -{ - m_events.removeHandler(CEvent::kTimer, m_quitTimeoutTimer); - delete m_quitTimeoutTimer; - m_quitTimeoutTimer = nullptr; -} - -void -CIpcTests::handleQuitTimeout(const CEvent&, void* vclient) -{ - LOG((CLOG_ERR "timeout")); - raiseQuitEvent(); -} diff --git a/src/test/integtests/CMakeLists.txt b/src/test/integtests/CMakeLists.txt index 042c6015..ddebe311 100644 --- a/src/test/integtests/CMakeLists.txt +++ b/src/test/integtests/CMakeLists.txt @@ -14,9 +14,16 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +set(h + CTestEventQueue.h +) + set(src + ${h} Main.cpp CIpcTests.cpp + NetworkTests.cpp + CTestEventQueue.cpp ) if (WIN32) @@ -50,11 +57,11 @@ set(inc ../../lib/mt ../../lib/net ../../lib/platform + ../../lib/server ../../lib/synergy ../../../tools/gtest-1.6.0/include ../../../tools/gmock-1.6.0/include ../unittests - ../unittests/synergy ) if (UNIX) @@ -72,4 +79,4 @@ endif() include_directories(${inc}) add_executable(integtests ${src}) target_link_libraries(integtests - arch base client common io ipc mt net platform server synergy gtest gmock ${libs}) + arch base client common io ipc mt net platform server synergy gtest gmock cryptopp ${libs}) diff --git a/src/test/integtests/CTestEventQueue.cpp b/src/test/integtests/CTestEventQueue.cpp new file mode 100644 index 00000000..f6cde4da --- /dev/null +++ b/src/test/integtests/CTestEventQueue.cpp @@ -0,0 +1,52 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2013 Bolton Software 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 "CTestEventQueue.h" +#include "CLog.h" +#include "TMethodEventJob.h" +#include "CSimpleEventQueueBuffer.h" + +void +CTestEventQueue::raiseQuitEvent() +{ + addEvent(CEvent(CEvent::kQuit)); +} + +void +CTestEventQueue::initQuitTimeout(double timeout) +{ + assert(m_quitTimeoutTimer == nullptr); + m_quitTimeoutTimer = newOneShotTimer(timeout, NULL); + adoptHandler(CEvent::kTimer, m_quitTimeoutTimer, + new TMethodEventJob( + this, &CTestEventQueue::handleQuitTimeout)); +} + +void +CTestEventQueue::cleanupQuitTimeout() +{ + removeHandler(CEvent::kTimer, m_quitTimeoutTimer); + delete m_quitTimeoutTimer; + m_quitTimeoutTimer = nullptr; +} + +void +CTestEventQueue::handleQuitTimeout(const CEvent&, void* vclient) +{ + LOG((CLOG_ERR "timeout")); + raiseQuitEvent(); +} diff --git a/src/test/integtests/CTestEventQueue.h b/src/test/integtests/CTestEventQueue.h new file mode 100644 index 00000000..82dd32d1 --- /dev/null +++ b/src/test/integtests/CTestEventQueue.h @@ -0,0 +1,38 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2013 Bolton Software 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 "CEventQueue.h" + +class CEventQueueTimer; + +class CTestEventQueue : public CEventQueue { +public: + CTestEventQueue() : m_quitTimeoutTimer(nullptr) { } + + void handleQuitTimeout(const CEvent&, void* vclient); + void raiseQuitEvent(); + void initQuitTimeout(double timeout); + void cleanupQuitTimeout(); + +private: + void timeoutThread(void*); + +private: + CEventQueueTimer* m_quitTimeoutTimer; +}; diff --git a/src/test/integtests/NetworkTests.cpp b/src/test/integtests/NetworkTests.cpp new file mode 100644 index 00000000..195ad80c --- /dev/null +++ b/src/test/integtests/NetworkTests.cpp @@ -0,0 +1,188 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2013 Bolton Software 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 +#include +#include + +#define TEST_ENV + +#include "CLog.h" +#include "CServer.h" +#include "CClient.h" +#include "TMethodEventJob.h" +#include "server/CMockConfig.h" +#include "server/CMockPrimaryClient.h" +#include "synergy/CMockScreen.h" +#include "CClientListener.h" +#include "CNetworkAddress.h" +#include "CTCPSocketFactory.h" +#include "CCryptoOptions.h" +#include "CSocketMultiplexer.h" +#include "CMSWindowsScreen.h" +#include "CGameDevice.h" +#include "CThread.h" +#include "TMethodJob.h" +#include "CTestEventQueue.h" +#include "server/CMockInputFilter.h" + +using ::testing::_; +using ::testing::NiceMock; +using ::testing::Return; +using ::testing::Invoke; + +#define TEST_PORT 24803 +#define TEST_HOST "localhost" + +const int klargeDataSize = 512; +char g_largeData[klargeDataSize] = "large data:head.1221412312341244213123fdsfasdawdwadwadacwdd.12321412312341244213123fdsfasdawdwadwadacwdawddawdwacawdawd232141231awddawdwacawdawd2321412312341244213123fdsfasdawdwadacwdawddawdwacawdtrtetawdawdwaewe1213412321412312341244213123fdsfasdawdwadacwdawddawdwacawdawdawdwaewe121341awdwaewedacwdawddawdwacawdawd2321412312341244213123fdsfasdawdwadacwdawddawdwacawdtrtetawdawdwaewe1213412321412312341244213123fdsfasdawdwadacwdawddawdwacawdawdawdwaewe121341awdwaewe12134123njk1u31i2nm3e123hu23oi132213njk.tail"; + +void sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h); +void sendFileToClient_getCursorPos(SInt32& x, SInt32& y); + +class NetworkTests : public ::testing::Test +{ +public: + NetworkTests() { } + + void sendData(CServer* server); + + void sendFileToClient_handleClientConnected(const CEvent&, void* vlistener); + void sendFileToClient_fileRecieveComplete(const CEvent&, void*); + +public: + CTestEventQueue m_events; +}; + +TEST_F(NetworkTests, sendFileToClient) +{ + // server and client + CNetworkAddress serverAddress(TEST_HOST, TEST_PORT); + CCryptoOptions cryptoOptions; + + serverAddress.resolve(); + + // server + CSocketMultiplexer serverSocketMultiplexer; + CTCPSocketFactory* serverSocketFactory = new CTCPSocketFactory(&m_events, &serverSocketMultiplexer); + CClientListener listener(serverAddress, serverSocketFactory, NULL, cryptoOptions, &m_events); + NiceMock serverScreen; + NiceMock primaryClient; + NiceMock serverConfig; + NiceMock serverInputFilter; + + m_events.adoptHandler( + m_events.forCClientListener().connected(), &listener, + new TMethodEventJob( + this, &NetworkTests::sendFileToClient_handleClientConnected, &listener)); + + ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); + ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); + + CServer server(serverConfig, &primaryClient, &serverScreen, &m_events); + server.m_mock = true; + listener.setServer(&server); + + // client + NiceMock clientScreen; + CSocketMultiplexer clientSocketMultiplexer; + CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer); + + ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(sendFileToClient_getShape)); + ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(sendFileToClient_getCursorPos)); + + CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions); + + m_events.adoptHandler( + m_events.forIScreen().fileRecieveComplete(), &client, + new TMethodEventJob( + this, &NetworkTests::sendFileToClient_fileRecieveComplete)); + + client.connect(); + + m_events.initQuitTimeout(10); + m_events.loop(); + m_events.cleanupQuitTimeout(); +} + +void +NetworkTests::sendFileToClient_handleClientConnected(const CEvent&, void* vlistener) +{ + CClientListener* listener = reinterpret_cast(vlistener); + CServer* server = listener->getServer(); + + CClientProxy* client = listener->getNextClient(); + if (client == NULL) { + throw std::exception("client is null"); + } + + CBaseClientProxy* bcp = reinterpret_cast(client); + server->adoptClient(bcp); + server->setActive(bcp); + + sendData(server); +} + +void +NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*) +{ + CClient* client = reinterpret_cast(event.getTarget()); + EXPECT_TRUE(client->isReceivedFileSizeValid()); + + m_events.raiseQuitEvent(); +} + +void +NetworkTests::sendData(CServer* server) +{ + UInt8* largeDataSize = new UInt8[5]; + largeDataSize[0] = '0'; + largeDataSize[1] = '5'; + largeDataSize[2] = '1'; + largeDataSize[3] = '1'; + largeDataSize[4] = '\0'; + + // transfer data from server -> client + m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, largeDataSize)); + + UInt8* largeData = new UInt8[klargeDataSize + 1]; + largeData[0] = '1'; + memcpy(&largeData[1], g_largeData, klargeDataSize); + m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, (UInt8*)largeData)); + + UInt8* transferFinished = new UInt8[2]; + transferFinished[0] = '2'; + transferFinished[1] = '\0'; + + m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, transferFinished)); +} + +void +sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) +{ + x = 0; + y = 0; + w = 1; + h = 1; +} + +void +sendFileToClient_getCursorPos(SInt32& x, SInt32& y) +{ + x = 0; + y = 0; +} diff --git a/src/test/integtests/platform/CMSWindowsKeyStateTests.cpp b/src/test/integtests/platform/CMSWindowsKeyStateTests.cpp index 322fd3ff..26945888 100644 --- a/src/test/integtests/platform/CMSWindowsKeyStateTests.cpp +++ b/src/test/integtests/platform/CMSWindowsKeyStateTests.cpp @@ -27,8 +27,8 @@ #include "CMSWindowsScreen.h" #include "CMSWindowsScreenSaver.h" #include "TMethodJob.h" -#include "CMockEventQueue.h" -#include "CMockKeyMap.h" +#include "synergy/CMockEventQueue.h" +#include "synergy/CMockKeyMap.h" // wParam = flags, HIBYTE(lParam) = virtual key, LOBYTE(lParam) = scan code #define SYNERGY_MSG_FAKE_KEY SYNERGY_HOOK_LAST_MSG + 4 diff --git a/src/test/unittests/CMakeLists.txt b/src/test/unittests/CMakeLists.txt index 441eb1ac..667bdc5c 100644 --- a/src/test/unittests/CMakeLists.txt +++ b/src/test/unittests/CMakeLists.txt @@ -22,6 +22,10 @@ set(h io/CMockStream.h server/CMockServer.h io/CMockCryptoStream.h + synergy/CMockScreen.h + server/CMockConfig.h + server/CMockPrimaryClient.h + server/CMockInputFilter.h ) set(src diff --git a/src/test/unittests/io/CMockCryptoStream.h b/src/test/unittests/io/CMockCryptoStream.h index 33f5e0d8..161c61a8 100644 --- a/src/test/unittests/io/CMockCryptoStream.h +++ b/src/test/unittests/io/CMockCryptoStream.h @@ -26,7 +26,6 @@ class CMockCryptoStream : public CCryptoStream public: CMockCryptoStream(IEventQueue* eventQueue, IStream* stream) : CCryptoStream(eventQueue, stream, CCryptoOptions("gcm", "stub"), false) { } - MOCK_METHOD2(read, UInt32(void*, UInt32)); MOCK_METHOD2(write, void(const void*, UInt32)); }; diff --git a/src/test/unittests/server/CMockConfig.h b/src/test/unittests/server/CMockConfig.h new file mode 100644 index 00000000..65bbcacd --- /dev/null +++ b/src/test/unittests/server/CMockConfig.h @@ -0,0 +1,31 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2013 Bolton Software 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 + +#define TEST_ENV +#include "CConfig.h" + +class CMockConfig : public CConfig +{ +public: + CMockConfig() : CConfig() { } + MOCK_METHOD0(getInputFilter, CInputFilter*()); + MOCK_CONST_METHOD1(isScreen, bool(const CString&)); +}; diff --git a/src/test/unittests/server/CMockInputFilter.h b/src/test/unittests/server/CMockInputFilter.h new file mode 100644 index 00000000..65813c76 --- /dev/null +++ b/src/test/unittests/server/CMockInputFilter.h @@ -0,0 +1,29 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2013 Bolton Software 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 + +#define TEST_ENV +#include "CInputFilter.h" + +class CMockInputFilter : public CInputFilter +{ +public: + MOCK_METHOD1(setPrimaryClient, void(CPrimaryClient*)); +}; diff --git a/src/test/unittests/server/CMockPrimaryClient.h b/src/test/unittests/server/CMockPrimaryClient.h new file mode 100644 index 00000000..88c9eeb3 --- /dev/null +++ b/src/test/unittests/server/CMockPrimaryClient.h @@ -0,0 +1,40 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2013 Bolton Software 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 + +#define TEST_ENV +#include "CPrimaryClient.h" +#include "CString.h" + +class CMockPrimaryClient : public CPrimaryClient +{ +public: + MOCK_CONST_METHOD0(getEventTarget, void*()); + MOCK_CONST_METHOD2(getCursorPos, void(SInt32&, SInt32&)); + MOCK_CONST_METHOD2(setJumpCursorPos, void(SInt32, SInt32)); + MOCK_METHOD1(reconfigure, void(UInt32)); + MOCK_METHOD0(resetOptions, void()); + MOCK_METHOD1(setOptions, void(const COptionsList&)); + MOCK_METHOD0(enable, void()); + MOCK_METHOD0(disable, void()); + MOCK_METHOD2(registerHotKey, UInt32(KeyID, KeyModifierMask)); + MOCK_CONST_METHOD0(getToggleMask, KeyModifierMask()); + MOCK_METHOD1(unregisterHotKey, void(UInt32)); +}; diff --git a/src/test/unittests/synergy/CMockScreen.h b/src/test/unittests/synergy/CMockScreen.h new file mode 100644 index 00000000..27f658b9 --- /dev/null +++ b/src/test/unittests/synergy/CMockScreen.h @@ -0,0 +1,35 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2013 Bolton Software 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 + +#define TEST_ENV +#include "CScreen.h" + +class CMockScreen : public CScreen +{ +public: + CMockScreen() : CScreen() { } + MOCK_METHOD0(disable, void()); + MOCK_CONST_METHOD4(getShape, void(SInt32&, SInt32&, SInt32&, SInt32&)); + MOCK_CONST_METHOD2(getCursorPos, void(SInt32&, SInt32&)); + MOCK_METHOD0(resetOptions, void()); + MOCK_METHOD1(setOptions, void(const COptionsList&)); + MOCK_METHOD0(enable, void()); +};