From 7010de9cc4b50f62908492aa31bc79debcced5ad Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Tue, 9 Apr 2013 18:56:19 +0000 Subject: [PATCH] sending IV to client before DKDN, DKUP and DKRP (the most sensitive messages). unit tests to support changes. made crypto stream tests a bit less spammy by using NiceMock. --- src/lib/client/CClient.cpp | 92 ++++++++------- src/lib/client/CClient.h | 22 ++-- src/lib/client/CServerProxy.cpp | 31 +++-- src/lib/client/CServerProxy.h | 11 +- src/lib/io/CStreamFilter.cpp | 10 +- src/lib/io/CStreamFilter.h | 2 +- src/lib/io/IStream.cpp | 17 ++- src/lib/io/IStream.h | 11 +- src/lib/server/CClientListener.cpp | 2 +- src/lib/server/CClientProxy.h | 9 +- src/lib/server/CClientProxy1_0.cpp | 46 +++++--- src/lib/server/CClientProxy1_0.h | 5 +- src/lib/server/CClientProxy1_1.cpp | 4 +- src/lib/server/CClientProxy1_1.h | 2 +- src/lib/server/CClientProxy1_2.cpp | 4 +- src/lib/server/CClientProxy1_2.h | 4 +- src/lib/server/CClientProxy1_3.cpp | 4 +- src/lib/server/CClientProxy1_3.h | 2 +- src/lib/server/CClientProxy1_4.cpp | 42 ++++++- src/lib/server/CClientProxy1_4.h | 8 +- src/lib/server/CClientProxyUnknown.cpp | 10 +- src/lib/server/CServer.cpp | 5 + src/lib/server/CServer.h | 7 ++ src/lib/synergy/CClientApp.cpp | 2 +- src/lib/synergy/CCryptoStream.cpp | 2 +- src/lib/synergy/CCryptoStream.h | 2 +- src/lib/synergy/CPacketStreamFilter.cpp | 2 +- src/lib/synergy/ProtocolTypes.cpp | 1 + src/lib/synergy/ProtocolTypes.h | 5 + src/test/unittests/CMakeLists.txt | 6 +- src/test/unittests/client/CMockClient.h | 7 +- .../unittests/client/CServerProxyTests.cpp | 111 ++++++++++-------- src/test/unittests/io/CMockCryptoStream.h | 29 +++++ src/test/unittests/io/CMockStream.h | 6 +- .../unittests/server/CClientProxyTests.cpp | 96 +++++++++++++++ src/test/unittests/server/CMockServer.h | 31 +++++ .../unittests/synergy/CCryptoStreamTests.cpp | 67 +++-------- 37 files changed, 490 insertions(+), 227 deletions(-) create mode 100644 src/test/unittests/io/CMockCryptoStream.h create mode 100644 src/test/unittests/server/CClientProxyTests.cpp create mode 100644 src/test/unittests/server/CMockServer.h diff --git a/src/lib/client/CClient.cpp b/src/lib/client/CClient.cpp index 5384c273..728d33e4 100644 --- a/src/lib/client/CClient.cpp +++ b/src/lib/client/CClient.cpp @@ -48,16 +48,12 @@ CEvent::Type CClient::s_connectedEvent = CEvent::kUnknown; CEvent::Type CClient::s_connectionFailedEvent = CEvent::kUnknown; CEvent::Type CClient::s_disconnectedEvent = CEvent::kUnknown; -CClient::CClient(IEventQueue& eventQueue) : - m_eventQueue(eventQueue) -{ -} - -CClient::CClient(IEventQueue& eventQueue, +CClient::CClient(IEventQueue* eventQueue, const CString& name, const CNetworkAddress& address, ISocketFactory* socketFactory, IStreamFilterFactory* streamFilterFactory, CScreen* screen) : + m_mock(false), m_name(name), m_serverAddress(address), m_socketFactory(socketFactory), @@ -71,25 +67,25 @@ CClient::CClient(IEventQueue& eventQueue, m_suspended(false), m_connectOnResume(false), m_eventQueue(eventQueue), - m_mock(false) + m_cryptoStream(NULL) { assert(m_socketFactory != NULL); assert(m_screen != NULL); // register suspend/resume event handlers - m_eventQueue.adoptHandler(IScreen::getSuspendEvent(), + m_eventQueue->adoptHandler(IScreen::getSuspendEvent(), getEventTarget(), new TMethodEventJob(this, &CClient::handleSuspend)); - m_eventQueue.adoptHandler(IScreen::getResumeEvent(), + m_eventQueue->adoptHandler(IScreen::getResumeEvent(), getEventTarget(), new TMethodEventJob(this, &CClient::handleResume)); - EVENTQUEUE->adoptHandler(IPlatformScreen::getGameDeviceTimingRespEvent(), + m_eventQueue->adoptHandler(IPlatformScreen::getGameDeviceTimingRespEvent(), getEventTarget(), new TMethodEventJob(this, &CClient::handleGameDeviceTimingResp)); - EVENTQUEUE->adoptHandler(IPlatformScreen::getGameDeviceFeedbackEvent(), + m_eventQueue->adoptHandler(IPlatformScreen::getGameDeviceFeedbackEvent(), getEventTarget(), new TMethodEventJob(this, &CClient::handleGameDeviceFeedback)); @@ -97,13 +93,13 @@ CClient::CClient(IEventQueue& eventQueue, CClient::~CClient() { - // HACK: can't disable dtor with mocks - if (m_mock) + if (m_mock) { return; + } - m_eventQueue.removeHandler(IScreen::getSuspendEvent(), + m_eventQueue->removeHandler(IScreen::getSuspendEvent(), getEventTarget()); - m_eventQueue.removeHandler(IScreen::getResumeEvent(), + m_eventQueue->removeHandler(IScreen::getResumeEvent(), getEventTarget()); cleanupTimer(); @@ -153,9 +149,9 @@ CClient::connect() m_stream = new CPacketStreamFilter(m_stream, true); if (s_cryptoEnabled) { - CCryptoStream* cryptoStream = new CCryptoStream(*EVENTQUEUE, m_stream, true); - cryptoStream->setKeyWithIv(g_key, sizeof(g_key), g_iv); - m_stream = cryptoStream; + m_cryptoStream = new CCryptoStream(m_eventQueue, m_stream, true); + m_cryptoStream->setKeyWithIv(g_key, sizeof(g_key), g_iv); + m_stream = m_cryptoStream; } // connect @@ -199,6 +195,14 @@ CClient::handshakeComplete() sendEvent(getConnectedEvent(), NULL); } +void +CClient::setCryptoIv(const UInt8* iv) +{ + if (m_cryptoStream != NULL) { + m_cryptoStream->setIv(iv); + } +} + bool CClient::isConnected() const { @@ -444,7 +448,7 @@ CClient::sendClipboard(ClipboardID id) void CClient::sendEvent(CEvent::Type type, void* data) { - m_eventQueue.addEvent(CEvent(type, getEventTarget(), data)); + m_eventQueue->addEvent(CEvent(type, getEventTarget(), data)); } void @@ -453,7 +457,7 @@ CClient::sendConnectionFailedEvent(const char* msg) CFailInfo* info = new CFailInfo(msg); info->m_retry = true; CEvent event(getConnectionFailedEvent(), getEventTarget(), info, CEvent::kDontFreeData); - EVENTQUEUE->addEvent(event); + m_eventQueue->addEvent(event); } void @@ -461,11 +465,11 @@ CClient::setupConnecting() { assert(m_stream != NULL); - m_eventQueue.adoptHandler(IDataSocket::getConnectedEvent(), + m_eventQueue->adoptHandler(IDataSocket::getConnectedEvent(), m_stream->getEventTarget(), new TMethodEventJob(this, &CClient::handleConnected)); - m_eventQueue.adoptHandler(IDataSocket::getConnectionFailedEvent(), + m_eventQueue->adoptHandler(IDataSocket::getConnectionFailedEvent(), m_stream->getEventTarget(), new TMethodEventJob(this, &CClient::handleConnectionFailed)); @@ -476,23 +480,23 @@ CClient::setupConnection() { assert(m_stream != NULL); - m_eventQueue.adoptHandler(ISocket::getDisconnectedEvent(), + m_eventQueue->adoptHandler(ISocket::getDisconnectedEvent(), m_stream->getEventTarget(), new TMethodEventJob(this, &CClient::handleDisconnected)); - m_eventQueue.adoptHandler(m_stream->getInputReadyEvent(), + m_eventQueue->adoptHandler(m_stream->getInputReadyEvent(), m_stream->getEventTarget(), new TMethodEventJob(this, &CClient::handleHello)); - m_eventQueue.adoptHandler(m_stream->getOutputErrorEvent(), + m_eventQueue->adoptHandler(m_stream->getOutputErrorEvent(), m_stream->getEventTarget(), new TMethodEventJob(this, &CClient::handleOutputError)); - m_eventQueue.adoptHandler(m_stream->getInputShutdownEvent(), + m_eventQueue->adoptHandler(m_stream->getInputShutdownEvent(), m_stream->getEventTarget(), new TMethodEventJob(this, &CClient::handleDisconnected)); - m_eventQueue.adoptHandler(m_stream->getOutputShutdownEvent(), + m_eventQueue->adoptHandler(m_stream->getOutputShutdownEvent(), m_stream->getEventTarget(), new TMethodEventJob(this, &CClient::handleDisconnected)); @@ -504,12 +508,12 @@ CClient::setupScreen() assert(m_server == NULL); m_ready = false; - m_server = new CServerProxy(this, m_stream, *EVENTQUEUE); - m_eventQueue.adoptHandler(IScreen::getShapeChangedEvent(), + m_server = new CServerProxy(this, m_stream, m_eventQueue); + m_eventQueue->adoptHandler(IScreen::getShapeChangedEvent(), getEventTarget(), new TMethodEventJob(this, &CClient::handleShapeChanged)); - m_eventQueue.adoptHandler(IScreen::getClipboardGrabbedEvent(), + m_eventQueue->adoptHandler(IScreen::getClipboardGrabbedEvent(), getEventTarget(), new TMethodEventJob(this, &CClient::handleClipboardGrabbed)); @@ -520,8 +524,8 @@ CClient::setupTimer() { assert(m_timer == NULL); - m_timer = m_eventQueue.newOneShotTimer(15.0, NULL); - m_eventQueue.adoptHandler(CEvent::kTimer, m_timer, + m_timer = m_eventQueue->newOneShotTimer(15.0, NULL); + m_eventQueue->adoptHandler(CEvent::kTimer, m_timer, new TMethodEventJob(this, &CClient::handleConnectTimeout)); } @@ -530,9 +534,9 @@ void CClient::cleanupConnecting() { if (m_stream != NULL) { - m_eventQueue.removeHandler(IDataSocket::getConnectedEvent(), + m_eventQueue->removeHandler(IDataSocket::getConnectedEvent(), m_stream->getEventTarget()); - m_eventQueue.removeHandler(IDataSocket::getConnectionFailedEvent(), + m_eventQueue->removeHandler(IDataSocket::getConnectionFailedEvent(), m_stream->getEventTarget()); } } @@ -541,15 +545,15 @@ void CClient::cleanupConnection() { if (m_stream != NULL) { - m_eventQueue.removeHandler(m_stream->getInputReadyEvent(), + m_eventQueue->removeHandler(m_stream->getInputReadyEvent(), m_stream->getEventTarget()); - m_eventQueue.removeHandler(m_stream->getOutputErrorEvent(), + m_eventQueue->removeHandler(m_stream->getOutputErrorEvent(), m_stream->getEventTarget()); - m_eventQueue.removeHandler(m_stream->getInputShutdownEvent(), + m_eventQueue->removeHandler(m_stream->getInputShutdownEvent(), m_stream->getEventTarget()); - m_eventQueue.removeHandler(m_stream->getOutputShutdownEvent(), + m_eventQueue->removeHandler(m_stream->getOutputShutdownEvent(), m_stream->getEventTarget()); - m_eventQueue.removeHandler(ISocket::getDisconnectedEvent(), + m_eventQueue->removeHandler(ISocket::getDisconnectedEvent(), m_stream->getEventTarget()); delete m_stream; m_stream = NULL; @@ -564,9 +568,9 @@ CClient::cleanupScreen() m_screen->disable(); m_ready = false; } - m_eventQueue.removeHandler(IScreen::getShapeChangedEvent(), + m_eventQueue->removeHandler(IScreen::getShapeChangedEvent(), getEventTarget()); - m_eventQueue.removeHandler(IScreen::getClipboardGrabbedEvent(), + m_eventQueue->removeHandler(IScreen::getClipboardGrabbedEvent(), getEventTarget()); delete m_server; m_server = NULL; @@ -577,8 +581,8 @@ void CClient::cleanupTimer() { if (m_timer != NULL) { - m_eventQueue.removeHandler(CEvent::kTimer, m_timer); - m_eventQueue.deleteTimer(m_timer); + m_eventQueue->removeHandler(CEvent::kTimer, m_timer); + m_eventQueue->deleteTimer(m_timer); m_timer = NULL; } } @@ -708,7 +712,7 @@ CClient::handleHello(const CEvent&, void*) // receive another event for already pending messages so we fake // one. if (m_stream->isReady()) { - m_eventQueue.addEvent(CEvent(m_stream->getInputReadyEvent(), + m_eventQueue->addEvent(CEvent(m_stream->getInputReadyEvent(), m_stream->getEventTarget())); } } diff --git a/src/lib/client/CClient.h b/src/lib/client/CClient.h index 08db693c..c6d35a0f 100644 --- a/src/lib/client/CClient.h +++ b/src/lib/client/CClient.h @@ -32,6 +32,7 @@ class ISocketFactory; namespace synergy { class IStream; } class IStreamFilterFactory; class IEventQueue; +class CCryptoStream; //! Synergy client /*! @@ -46,21 +47,22 @@ public: CString m_what; }; -protected: - CClient(IEventQueue& eventQueue); - public: /*! This client will attempt to connect to the server using \p name as its name and \p address as the server's address and \p factory to create the socket. \p screen is the local screen. */ - CClient(IEventQueue& eventQueue, + CClient(IEventQueue* eventQueue, const CString& name, const CNetworkAddress& address, ISocketFactory* socketFactory, IStreamFilterFactory* streamFilterFactory, CScreen* screen); ~CClient(); + +#ifdef TEST_ENV + CClient() { } +#endif //! @name manipulators //@{ @@ -82,7 +84,10 @@ public: /*! Notifies the client that the connection handshake has completed. */ - void handshakeComplete(); + virtual void handshakeComplete(); + + //! Set crypto IV + virtual void setCryptoIv(const UInt8* iv); //@} //! @name accessors @@ -190,6 +195,9 @@ private: void handleGameDeviceTimingResp(const CEvent& event, void*); void handleGameDeviceFeedback(const CEvent& event, void*); +public: + bool m_mock; + private: CString m_name; CNetworkAddress m_serverAddress; @@ -207,8 +215,8 @@ private: bool m_sentClipboard[kClipboardEnd]; IClipboard::Time m_timeClipboard[kClipboardEnd]; CString m_dataClipboard[kClipboardEnd]; - IEventQueue& m_eventQueue; - bool m_mock; + IEventQueue* m_eventQueue; + CCryptoStream* m_cryptoStream; static CEvent::Type s_connectedEvent; static CEvent::Type s_connectionFailedEvent; diff --git a/src/lib/client/CServerProxy.cpp b/src/lib/client/CServerProxy.cpp index 39f54e5a..682f286a 100644 --- a/src/lib/client/CServerProxy.cpp +++ b/src/lib/client/CServerProxy.cpp @@ -35,10 +35,9 @@ // CServerProxy // -CServerProxy::CServerProxy(CClient* client, synergy::IStream* stream, IEventQueue& eventQueue) : +CServerProxy::CServerProxy(CClient* client, synergy::IStream* stream, IEventQueue* eventQueue) : m_client(client), m_stream(stream), - m_cryptoStream(NULL), m_seqNum(0), m_compressMouse(false), m_compressMouseRelative(false), @@ -60,7 +59,7 @@ CServerProxy::CServerProxy(CClient* client, synergy::IStream* stream, IEventQueu m_modifierTranslationTable[id] = id; // handle data on stream - m_eventQueue.adoptHandler(m_stream->getInputReadyEvent(), + m_eventQueue->adoptHandler(m_stream->getInputReadyEvent(), m_stream->getEventTarget(), new TMethodEventJob(this, &CServerProxy::handleData)); @@ -72,7 +71,7 @@ CServerProxy::CServerProxy(CClient* client, synergy::IStream* stream, IEventQueu CServerProxy::~CServerProxy() { setKeepAliveRate(-1.0); - m_eventQueue.removeHandler(m_stream->getInputReadyEvent(), + m_eventQueue->removeHandler(m_stream->getInputReadyEvent(), m_stream->getEventTarget()); } @@ -80,14 +79,14 @@ void CServerProxy::resetKeepAliveAlarm() { if (m_keepAliveAlarmTimer != NULL) { - m_eventQueue.removeHandler(CEvent::kTimer, m_keepAliveAlarmTimer); - m_eventQueue.deleteTimer(m_keepAliveAlarmTimer); + m_eventQueue->removeHandler(CEvent::kTimer, m_keepAliveAlarmTimer); + m_eventQueue->deleteTimer(m_keepAliveAlarmTimer); m_keepAliveAlarmTimer = NULL; } if (m_keepAliveAlarm > 0.0) { m_keepAliveAlarmTimer = - m_eventQueue.newOneShotTimer(m_keepAliveAlarm, NULL); - m_eventQueue.adoptHandler(CEvent::kTimer, m_keepAliveAlarmTimer, + m_eventQueue->newOneShotTimer(m_keepAliveAlarm, NULL); + m_eventQueue->adoptHandler(CEvent::kTimer, m_keepAliveAlarmTimer, new TMethodEventJob(this, &CServerProxy::handleKeepAliveAlarm)); } @@ -306,6 +305,10 @@ CServerProxy::parseMessage(const UInt8* code) gameDeviceTimingReq(); } + else if (memcmp(code, kMsgDCryptoIv, 4) == 0) { + cryptoIv(); + } + else if (memcmp(code, kMsgCClose, 4) == 0) { // server wants us to hangup LOG((CLOG_DEBUG1 "recv close")); @@ -826,6 +829,18 @@ CServerProxy::gameDeviceTimingReq() m_client->gameDeviceTimingReq(); } +void +CServerProxy::cryptoIv() +{ + // parse + CString s; + CProtocolUtil::readf(m_stream, kMsgDCryptoIv + 4, &s); + LOG((CLOG_DEBUG2 "recv crypto iv size=%i", s.size())); + + // forward + m_client->setCryptoIv(reinterpret_cast(s.c_str())); +} + void CServerProxy::screensaver() { diff --git a/src/lib/client/CServerProxy.h b/src/lib/client/CServerProxy.h index d2c5be09..5d1a9504 100644 --- a/src/lib/client/CServerProxy.h +++ b/src/lib/client/CServerProxy.h @@ -30,7 +30,6 @@ class CEventQueueTimer; class IClipboard; namespace synergy { class IStream; } class IEventQueue; -class CCryptoStream; //! Proxy for server /*! @@ -43,7 +42,7 @@ public: Process messages from the server on \p stream and forward to \p client. */ - CServerProxy(CClient* client, synergy::IStream* stream, IEventQueue& eventQueue); + CServerProxy(CClient* client, synergy::IStream* stream, IEventQueue* eventQueue); ~CServerProxy(); //! @name manipulators @@ -57,6 +56,10 @@ public: //@} +#ifdef TEST_ENV + void handleDataForTest() { handleData(NULL, NULL); } +#endif + protected: enum EResult { kOkay, kUnknown, kDisconnect }; EResult parseHandshakeMessage(const UInt8* code); @@ -96,6 +99,7 @@ private: void gameDeviceSticks(); void gameDeviceTriggers(); void gameDeviceTimingReq(); + void cryptoIv(); void screensaver(); void resetOptions(); void setOptions(); @@ -107,7 +111,6 @@ private: CClient* m_client; synergy::IStream* m_stream; - CCryptoStream* m_cryptoStream; UInt32 m_seqNum; @@ -124,7 +127,7 @@ private: CEventQueueTimer* m_keepAliveAlarmTimer; MessageParser m_parser; - IEventQueue& m_eventQueue; + IEventQueue* m_eventQueue; }; #endif diff --git a/src/lib/io/CStreamFilter.cpp b/src/lib/io/CStreamFilter.cpp index 41669570..569100d1 100644 --- a/src/lib/io/CStreamFilter.cpp +++ b/src/lib/io/CStreamFilter.cpp @@ -24,21 +24,21 @@ // CStreamFilter // -CStreamFilter::CStreamFilter(IEventQueue& eventQueue, synergy::IStream* stream, bool adoptStream) : +CStreamFilter::CStreamFilter(IEventQueue* eventQueue, synergy::IStream* stream, bool adoptStream) : IStream(eventQueue), m_stream(stream), m_adopted(adoptStream) { // replace handlers for m_stream - m_eventQueue.removeHandlers(m_stream->getEventTarget()); - m_eventQueue.adoptHandler(CEvent::kUnknown, m_stream->getEventTarget(), + getEventQueue().removeHandlers(m_stream->getEventTarget()); + getEventQueue().adoptHandler(CEvent::kUnknown, m_stream->getEventTarget(), new TMethodEventJob(this, &CStreamFilter::handleUpstreamEvent)); } CStreamFilter::~CStreamFilter() { - m_eventQueue.removeHandler(CEvent::kUnknown, m_stream->getEventTarget()); + getEventQueue().removeHandler(CEvent::kUnknown, m_stream->getEventTarget()); if (m_adopted) { delete m_stream; } @@ -107,7 +107,7 @@ CStreamFilter::getStream() const void CStreamFilter::filterEvent(const CEvent& event) { - m_eventQueue.dispatchEvent(CEvent(event.getType(), + getEventQueue().dispatchEvent(CEvent(event.getType(), getEventTarget(), event.getData())); } diff --git a/src/lib/io/CStreamFilter.h b/src/lib/io/CStreamFilter.h index deb71193..d85bc195 100644 --- a/src/lib/io/CStreamFilter.h +++ b/src/lib/io/CStreamFilter.h @@ -34,7 +34,7 @@ public: this object takes ownership of the stream and will delete it in the d'tor. */ - CStreamFilter(IEventQueue& eventQueue, synergy::IStream* stream, bool adoptStream = true); + CStreamFilter(IEventQueue* eventQueue, synergy::IStream* stream, bool adoptStream = true); virtual ~CStreamFilter(); // IStream overrides diff --git a/src/lib/io/IStream.cpp b/src/lib/io/IStream.cpp index 5df2009d..9bf1f634 100644 --- a/src/lib/io/IStream.cpp +++ b/src/lib/io/IStream.cpp @@ -34,34 +34,41 @@ CEvent::Type IStream::s_outputShutdownEvent = CEvent::kUnknown; CEvent::Type IStream::getInputReadyEvent() { - return m_eventQueue.registerTypeOnce(s_inputReadyEvent, + return m_eventQueue->registerTypeOnce(s_inputReadyEvent, "IStream::inputReady"); } CEvent::Type IStream::getOutputFlushedEvent() { - return m_eventQueue.registerTypeOnce(s_outputFlushedEvent, + return m_eventQueue->registerTypeOnce(s_outputFlushedEvent, "IStream::outputFlushed"); } CEvent::Type IStream::getOutputErrorEvent() { - return m_eventQueue.registerTypeOnce(s_outputErrorEvent, + return m_eventQueue->registerTypeOnce(s_outputErrorEvent, "IStream::outputError"); } CEvent::Type IStream::getInputShutdownEvent() { - return m_eventQueue.registerTypeOnce(s_inputShutdownEvent, + return m_eventQueue->registerTypeOnce(s_inputShutdownEvent, "IStream::inputShutdown"); } CEvent::Type IStream::getOutputShutdownEvent() { - return m_eventQueue.registerTypeOnce(s_outputShutdownEvent, + return m_eventQueue->registerTypeOnce(s_outputShutdownEvent, "IStream::outputShutdown"); } + +IEventQueue& +IStream::getEventQueue() const +{ + assert(m_eventQueue != NULL); + return *m_eventQueue; +} diff --git a/src/lib/io/IStream.h b/src/lib/io/IStream.h index 58e9de4e..7c667f7d 100644 --- a/src/lib/io/IStream.h +++ b/src/lib/io/IStream.h @@ -33,8 +33,8 @@ Defines the interface for all streams. */ class IStream : public IInterface { public: - IStream() : m_eventQueue(*EVENTQUEUE) { } - IStream(IEventQueue& eventQueue) : m_eventQueue(eventQueue) { } + IStream() : m_eventQueue(EVENTQUEUE) { } + IStream(IEventQueue* eventQueue) : m_eventQueue(eventQueue) { } //! @name manipulators //@{ @@ -156,9 +156,10 @@ public: */ virtual CEvent::Type getOutputShutdownEvent(); - //@} + //! Get the event queue + IEventQueue& getEventQueue() const; - IEventQueue& m_eventQueue; + //@} private: static CEvent::Type s_inputReadyEvent; @@ -166,6 +167,8 @@ private: static CEvent::Type s_outputErrorEvent; static CEvent::Type s_inputShutdownEvent; static CEvent::Type s_outputShutdownEvent; + + IEventQueue* m_eventQueue; }; } diff --git a/src/lib/server/CClientListener.cpp b/src/lib/server/CClientListener.cpp index 81dacdce..d4802199 100644 --- a/src/lib/server/CClientListener.cpp +++ b/src/lib/server/CClientListener.cpp @@ -150,7 +150,7 @@ CClientListener::handleClientConnecting(const CEvent&, void*) stream = new CPacketStreamFilter(stream, true); if (s_cryptoEnabled) { - CCryptoStream* cryptoStream = new CCryptoStream(*EVENTQUEUE, stream, true); + CCryptoStream* cryptoStream = new CCryptoStream(EVENTQUEUE, stream, true); cryptoStream->setKeyWithIv(g_key, sizeof(g_key), g_iv); stream = cryptoStream; } diff --git a/src/lib/server/CClientProxy.h b/src/lib/server/CClientProxy.h index 6fe6d22d..f9298eaa 100644 --- a/src/lib/server/CClientProxy.h +++ b/src/lib/server/CClientProxy.h @@ -25,8 +25,6 @@ namespace synergy { class IStream; } -const int g_encryptionEnabled = true; - //! Generic proxy for client class CClientProxy : public CBaseClientProxy { public: @@ -49,12 +47,6 @@ public: //! @name accessors //@{ - //! Get stream (unmodified) - /*! - Returns the original stream passed to the c'tor. - */ - synergy::IStream* getStreamUnmodified() const; - //! Get stream /*! Returns a crypto stream if the user has this enabled, @@ -125,6 +117,7 @@ public: virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2) = 0; virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2) = 0; virtual void gameDeviceTimingReq() = 0; + virtual void cryptoIv(const UInt8* iv) = 0; private: synergy::IStream* m_stream; diff --git a/src/lib/server/CClientProxy1_0.cpp b/src/lib/server/CClientProxy1_0.cpp index ea467483..ce35ba69 100644 --- a/src/lib/server/CClientProxy1_0.cpp +++ b/src/lib/server/CClientProxy1_0.cpp @@ -29,29 +29,30 @@ // CClientProxy1_0 // -CClientProxy1_0::CClientProxy1_0(const CString& name, synergy::IStream* stream) : +CClientProxy1_0::CClientProxy1_0(const CString& name, synergy::IStream* stream, IEventQueue* eventQueue) : CClientProxy(name, stream), m_heartbeatTimer(NULL), - m_parser(&CClientProxy1_0::parseHandshakeMessage) + m_parser(&CClientProxy1_0::parseHandshakeMessage), + m_eventQueue(eventQueue) { // install event handlers - EVENTQUEUE->adoptHandler(stream->getInputReadyEvent(), + m_eventQueue->adoptHandler(stream->getInputReadyEvent(), stream->getEventTarget(), new TMethodEventJob(this, &CClientProxy1_0::handleData, NULL)); - EVENTQUEUE->adoptHandler(stream->getOutputErrorEvent(), + m_eventQueue->adoptHandler(stream->getOutputErrorEvent(), stream->getEventTarget(), new TMethodEventJob(this, &CClientProxy1_0::handleWriteError, NULL)); - EVENTQUEUE->adoptHandler(stream->getInputShutdownEvent(), + m_eventQueue->adoptHandler(stream->getInputShutdownEvent(), stream->getEventTarget(), new TMethodEventJob(this, &CClientProxy1_0::handleDisconnect, NULL)); - EVENTQUEUE->adoptHandler(stream->getOutputShutdownEvent(), + m_eventQueue->adoptHandler(stream->getOutputShutdownEvent(), stream->getEventTarget(), new TMethodEventJob(this, &CClientProxy1_0::handleWriteError, NULL)); - EVENTQUEUE->adoptHandler(CEvent::kTimer, this, + m_eventQueue->adoptHandler(CEvent::kTimer, this, new TMethodEventJob(this, &CClientProxy1_0::handleFlatline, NULL)); @@ -71,22 +72,22 @@ CClientProxy1_0::disconnect() { removeHandlers(); getStream()->close(); - EVENTQUEUE->addEvent(CEvent(getDisconnectedEvent(), getEventTarget())); + m_eventQueue->addEvent(CEvent(getDisconnectedEvent(), getEventTarget())); } void CClientProxy1_0::removeHandlers() { // uninstall event handlers - EVENTQUEUE->removeHandler(getStream()->getInputReadyEvent(), + m_eventQueue->removeHandler(getStream()->getInputReadyEvent(), getStream()->getEventTarget()); - EVENTQUEUE->removeHandler(getStream()->getOutputErrorEvent(), + m_eventQueue->removeHandler(getStream()->getOutputErrorEvent(), getStream()->getEventTarget()); - EVENTQUEUE->removeHandler(getStream()->getInputShutdownEvent(), + m_eventQueue->removeHandler(getStream()->getInputShutdownEvent(), getStream()->getEventTarget()); - EVENTQUEUE->removeHandler(getStream()->getOutputShutdownEvent(), + m_eventQueue->removeHandler(getStream()->getOutputShutdownEvent(), getStream()->getEventTarget()); - EVENTQUEUE->removeHandler(CEvent::kTimer, this); + m_eventQueue->removeHandler(CEvent::kTimer, this); // remove timer removeHeartbeatTimer(); @@ -96,7 +97,7 @@ void CClientProxy1_0::addHeartbeatTimer() { if (m_heartbeatAlarm > 0.0) { - m_heartbeatTimer = EVENTQUEUE->newOneShotTimer(m_heartbeatAlarm, this); + m_heartbeatTimer = m_eventQueue->newOneShotTimer(m_heartbeatAlarm, this); } } @@ -104,7 +105,7 @@ void CClientProxy1_0::removeHeartbeatTimer() { if (m_heartbeatTimer != NULL) { - EVENTQUEUE->deleteTimer(m_heartbeatTimer); + m_eventQueue->deleteTimer(m_heartbeatTimer); m_heartbeatTimer = NULL; } } @@ -171,7 +172,7 @@ CClientProxy1_0::parseHandshakeMessage(const UInt8* code) // future messages get parsed by parseMessage m_parser = &CClientProxy1_0::parseMessage; if (recvInfo()) { - EVENTQUEUE->addEvent(CEvent(getReadyEvent(), getEventTarget())); + m_eventQueue->addEvent(CEvent(getReadyEvent(), getEventTarget())); addHeartbeatTimer(); return true; } @@ -184,7 +185,7 @@ CClientProxy1_0::parseMessage(const UInt8* code) { if (memcmp(code, kMsgDInfo, 4) == 0) { if (recvInfo()) { - EVENTQUEUE->addEvent( + m_eventQueue->addEvent( CEvent(getShapeChangedEvent(), getEventTarget())); return true; } @@ -385,6 +386,13 @@ CClientProxy1_0::gameDeviceTimingReq() LOG((CLOG_DEBUG "gameDeviceTimingReq not supported")); } +void +CClientProxy1_0::cryptoIv(const UInt8* iv) +{ + // ignore -- not supported in protocol 1.0 + LOG((CLOG_DEBUG "cryptoIv not supported")); +} + void CClientProxy1_0::screensaver(bool on) { @@ -484,7 +492,7 @@ CClientProxy1_0::recvClipboard() CClipboardInfo* info = new CClipboardInfo; info->m_id = id; info->m_sequenceNumber = seqNum; - EVENTQUEUE->addEvent(CEvent(getClipboardChangedEvent(), + m_eventQueue->addEvent(CEvent(getClipboardChangedEvent(), getEventTarget(), info)); return true; @@ -510,7 +518,7 @@ CClientProxy1_0::recvGrabClipboard() CClipboardInfo* info = new CClipboardInfo; info->m_id = id; info->m_sequenceNumber = seqNum; - EVENTQUEUE->addEvent(CEvent(getClipboardGrabbedEvent(), + m_eventQueue->addEvent(CEvent(getClipboardGrabbedEvent(), getEventTarget(), info)); return true; diff --git a/src/lib/server/CClientProxy1_0.h b/src/lib/server/CClientProxy1_0.h index 2b66e0dd..0e8fd333 100644 --- a/src/lib/server/CClientProxy1_0.h +++ b/src/lib/server/CClientProxy1_0.h @@ -25,11 +25,12 @@ class CEvent; class CEventQueueTimer; +class IEventQueue; //! Proxy for client implementing protocol version 1.0 class CClientProxy1_0 : public CClientProxy { public: - CClientProxy1_0(const CString& name, synergy::IStream* adoptedStream); + CClientProxy1_0(const CString& name, synergy::IStream* adoptedStream, IEventQueue* eventQueue); ~CClientProxy1_0(); // IScreen @@ -62,6 +63,7 @@ public: virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2); virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2); virtual void gameDeviceTimingReq(); + virtual void cryptoIv(const UInt8* iv); protected: virtual bool parseHandshakeMessage(const UInt8* code); @@ -103,6 +105,7 @@ private: double m_heartbeatAlarm; CEventQueueTimer* m_heartbeatTimer; MessageParser m_parser; + IEventQueue* m_eventQueue; }; #endif diff --git a/src/lib/server/CClientProxy1_1.cpp b/src/lib/server/CClientProxy1_1.cpp index 377a3f74..706b2fa2 100644 --- a/src/lib/server/CClientProxy1_1.cpp +++ b/src/lib/server/CClientProxy1_1.cpp @@ -25,8 +25,8 @@ // CClientProxy1_1 // -CClientProxy1_1::CClientProxy1_1(const CString& name, synergy::IStream* stream) : - CClientProxy1_0(name, stream) +CClientProxy1_1::CClientProxy1_1(const CString& name, synergy::IStream* stream, IEventQueue* eventQueue) : + CClientProxy1_0(name, stream, eventQueue) { // do nothing } diff --git a/src/lib/server/CClientProxy1_1.h b/src/lib/server/CClientProxy1_1.h index 2118694b..10e25d90 100644 --- a/src/lib/server/CClientProxy1_1.h +++ b/src/lib/server/CClientProxy1_1.h @@ -24,7 +24,7 @@ //! Proxy for client implementing protocol version 1.1 class CClientProxy1_1 : public CClientProxy1_0 { public: - CClientProxy1_1(const CString& name, synergy::IStream* adoptedStream); + CClientProxy1_1(const CString& name, synergy::IStream* adoptedStream, IEventQueue* eventQueue); ~CClientProxy1_1(); // IClient overrides diff --git a/src/lib/server/CClientProxy1_2.cpp b/src/lib/server/CClientProxy1_2.cpp index 7e6de36c..9919c128 100644 --- a/src/lib/server/CClientProxy1_2.cpp +++ b/src/lib/server/CClientProxy1_2.cpp @@ -24,8 +24,8 @@ // CClientProxy1_1 // -CClientProxy1_2::CClientProxy1_2(const CString& name, synergy::IStream* stream) : - CClientProxy1_1(name, stream) +CClientProxy1_2::CClientProxy1_2(const CString& name, synergy::IStream* stream, IEventQueue* eventQueue) : + CClientProxy1_1(name, stream, eventQueue) { // do nothing } diff --git a/src/lib/server/CClientProxy1_2.h b/src/lib/server/CClientProxy1_2.h index a89d5491..543be56f 100644 --- a/src/lib/server/CClientProxy1_2.h +++ b/src/lib/server/CClientProxy1_2.h @@ -21,10 +21,12 @@ #include "CClientProxy1_1.h" +class IEventQueue; + //! Proxy for client implementing protocol version 1.2 class CClientProxy1_2 : public CClientProxy1_1 { public: - CClientProxy1_2(const CString& name, synergy::IStream* adoptedStream); + CClientProxy1_2(const CString& name, synergy::IStream* adoptedStream, IEventQueue* eventQueue); ~CClientProxy1_2(); // IClient overrides diff --git a/src/lib/server/CClientProxy1_3.cpp b/src/lib/server/CClientProxy1_3.cpp index 74002faf..fcf452ff 100644 --- a/src/lib/server/CClientProxy1_3.cpp +++ b/src/lib/server/CClientProxy1_3.cpp @@ -28,8 +28,8 @@ // CClientProxy1_3 // -CClientProxy1_3::CClientProxy1_3(const CString& name, synergy::IStream* stream) : - CClientProxy1_2(name, stream), +CClientProxy1_3::CClientProxy1_3(const CString& name, synergy::IStream* stream, IEventQueue* eventQueue) : + CClientProxy1_2(name, stream, eventQueue), m_keepAliveRate(kKeepAliveRate), m_keepAliveTimer(NULL) { diff --git a/src/lib/server/CClientProxy1_3.h b/src/lib/server/CClientProxy1_3.h index fc5e6ab0..c5238016 100644 --- a/src/lib/server/CClientProxy1_3.h +++ b/src/lib/server/CClientProxy1_3.h @@ -24,7 +24,7 @@ //! Proxy for client implementing protocol version 1.3 class CClientProxy1_3 : public CClientProxy1_2 { public: - CClientProxy1_3(const CString& name, synergy::IStream* adoptedStream); + CClientProxy1_3(const CString& name, synergy::IStream* adoptedStream, IEventQueue* eventQueue); ~CClientProxy1_3(); // IClient overrides diff --git a/src/lib/server/CClientProxy1_4.cpp b/src/lib/server/CClientProxy1_4.cpp index ccbc7418..81d86208 100644 --- a/src/lib/server/CClientProxy1_4.cpp +++ b/src/lib/server/CClientProxy1_4.cpp @@ -24,13 +24,14 @@ #include #include #include "CServer.h" +#include "CCryptoStream.h" // // CClientProxy1_4 // -CClientProxy1_4::CClientProxy1_4(const CString& name, synergy::IStream* stream, CServer* server) : - CClientProxy1_3(name, stream), m_server(server) +CClientProxy1_4::CClientProxy1_4(const CString& name, synergy::IStream* stream, CServer* server, IEventQueue* eventQueue) : + CClientProxy1_3(name, stream, eventQueue), m_server(server) { assert(m_server != NULL); } @@ -67,6 +68,43 @@ CClientProxy1_4::gameDeviceTimingReq() CProtocolUtil::writef(getStream(), kMsgCGameTimingReq); } +void +CClientProxy1_4::keyDown(KeyID key, KeyModifierMask mask, KeyButton button) +{ + cryptoIv(); + CClientProxy1_3::keyDown(key, mask, button); +} + +void +CClientProxy1_4::keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button) +{ + cryptoIv(); + CClientProxy1_3::keyRepeat(key, mask, count, button); +} + +void +CClientProxy1_4::keyUp(KeyID key, KeyModifierMask mask, KeyButton button) +{ + cryptoIv(); + CClientProxy1_3::keyUp(key, mask, button); +} + +void +CClientProxy1_4::cryptoIv() +{ + CCryptoStream* cryptoStream = dynamic_cast(getStream()); + if (cryptoStream == NULL) { + return; + } + + byte iv[CRYPTO_IV_SIZE]; + cryptoStream->newIv(iv); + CString data(reinterpret_cast(iv), CRYPTO_IV_SIZE); + + LOG((CLOG_DEBUG2 "send crypto iv change to \"%s\"", getName().c_str())); + CProtocolUtil::writef(getStream(), kMsgDCryptoIv, &data); +} + bool CClientProxy1_4::parseMessage(const UInt8* code) { diff --git a/src/lib/server/CClientProxy1_4.h b/src/lib/server/CClientProxy1_4.h index 2701ddc6..d6d1238c 100644 --- a/src/lib/server/CClientProxy1_4.h +++ b/src/lib/server/CClientProxy1_4.h @@ -26,7 +26,7 @@ class CServer; //! Proxy for client implementing protocol version 1.4 class CClientProxy1_4 : public CClientProxy1_3 { public: - CClientProxy1_4(const CString& name, synergy::IStream* adoptedStream, CServer* server); + CClientProxy1_4(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* eventQueue); ~CClientProxy1_4(); // IClient overrides @@ -34,6 +34,12 @@ public: virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2); virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2); virtual void gameDeviceTimingReq(); + virtual void keyDown(KeyID key, KeyModifierMask mask, KeyButton button); + virtual void keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button); + virtual void keyUp(KeyID key, KeyModifierMask mask, KeyButton button); + + //! Send IV to make + void cryptoIv(); protected: // CClientProxy overrides diff --git a/src/lib/server/CClientProxyUnknown.cpp b/src/lib/server/CClientProxyUnknown.cpp index cbdc4b79..62b19064 100644 --- a/src/lib/server/CClientProxyUnknown.cpp +++ b/src/lib/server/CClientProxyUnknown.cpp @@ -219,23 +219,23 @@ CClientProxyUnknown::handleData(const CEvent&, void*) if (major == 1) { switch (minor) { case 0: - m_proxy = new CClientProxy1_0(name, m_stream); + m_proxy = new CClientProxy1_0(name, m_stream, EVENTQUEUE); break; case 1: - m_proxy = new CClientProxy1_1(name, m_stream); + m_proxy = new CClientProxy1_1(name, m_stream, EVENTQUEUE); break; case 2: - m_proxy = new CClientProxy1_2(name, m_stream); + m_proxy = new CClientProxy1_2(name, m_stream, EVENTQUEUE); break; case 3: - m_proxy = new CClientProxy1_3(name, m_stream); + m_proxy = new CClientProxy1_3(name, m_stream, EVENTQUEUE); break; case 4: - m_proxy = new CClientProxy1_4(name, m_stream, m_server); + m_proxy = new CClientProxy1_4(name, m_stream, m_server, EVENTQUEUE); break; } } diff --git a/src/lib/server/CServer.cpp b/src/lib/server/CServer.cpp index ddd8422b..b3e864fc 100644 --- a/src/lib/server/CServer.cpp +++ b/src/lib/server/CServer.cpp @@ -51,6 +51,7 @@ CEvent::Type CServer::s_lockCursorToScreen = CEvent::kUnknown; CEvent::Type CServer::s_screenSwitched = CEvent::kUnknown; CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient, CScreen* screen) : + m_mock(false), m_primaryClient(primaryClient), m_active(primaryClient), m_seqNum(0), @@ -202,6 +203,10 @@ CServer::CServer(const CConfig& config, CPrimaryClient* primaryClient, CScreen* CServer::~CServer() { + if (m_mock) { + return; + } + // remove event handlers and timers EVENTQUEUE->removeHandler(IPlatformScreen::getKeyDownEvent(*EVENTQUEUE), m_inputFilter); diff --git a/src/lib/server/CServer.h b/src/lib/server/CServer.h index aba54442..4b60fafa 100644 --- a/src/lib/server/CServer.h +++ b/src/lib/server/CServer.h @@ -103,6 +103,10 @@ public: */ CServer(const CConfig& config, CPrimaryClient* primaryClient, CScreen* screen); ~CServer(); + +#ifdef TEST_ENV + CServer() { } +#endif //! @name manipulators //@{ @@ -394,6 +398,9 @@ private: // force the cursor off of \p client void forceLeaveClient(CBaseClientProxy* client); + +public: + bool m_mock; private: class CClipboardInfo { diff --git a/src/lib/synergy/CClientApp.cpp b/src/lib/synergy/CClientApp.cpp index f42c0760..e2dd095e 100644 --- a/src/lib/synergy/CClientApp.cpp +++ b/src/lib/synergy/CClientApp.cpp @@ -396,7 +396,7 @@ CClient* CClientApp::openClient(const CString& name, const CNetworkAddress& address, CScreen* screen) { CClient* client = new CClient( - *EVENTQUEUE, name, address, new CTCPSocketFactory, NULL, screen); + EVENTQUEUE, name, address, new CTCPSocketFactory, NULL, screen); try { EVENTQUEUE->adoptHandler( diff --git a/src/lib/synergy/CCryptoStream.cpp b/src/lib/synergy/CCryptoStream.cpp index 639a8296..c161f794 100644 --- a/src/lib/synergy/CCryptoStream.cpp +++ b/src/lib/synergy/CCryptoStream.cpp @@ -22,7 +22,7 @@ using namespace CryptoPP; -CCryptoStream::CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream, bool adoptStream) : +CCryptoStream::CCryptoStream(IEventQueue* eventQueue, synergy::IStream* stream, bool adoptStream) : CStreamFilter(eventQueue, stream, adoptStream), m_key(NULL), m_keyLength(0) diff --git a/src/lib/synergy/CCryptoStream.h b/src/lib/synergy/CCryptoStream.h index 80ab007a..64d819b3 100644 --- a/src/lib/synergy/CCryptoStream.h +++ b/src/lib/synergy/CCryptoStream.h @@ -32,7 +32,7 @@ Encrypts (on write) and decrypts (on read) to and from an underlying stream. */ class CCryptoStream : public CStreamFilter { public: - CCryptoStream(IEventQueue& eventQueue, synergy::IStream* stream, bool adoptStream = true); + CCryptoStream(IEventQueue* eventQueue, synergy::IStream* stream, bool adoptStream = true); virtual ~CCryptoStream(); //! @name manipulators diff --git a/src/lib/synergy/CPacketStreamFilter.cpp b/src/lib/synergy/CPacketStreamFilter.cpp index 69437e5d..9ff89289 100644 --- a/src/lib/synergy/CPacketStreamFilter.cpp +++ b/src/lib/synergy/CPacketStreamFilter.cpp @@ -28,7 +28,7 @@ // CPacketStreamFilter::CPacketStreamFilter(synergy::IStream* stream, bool adoptStream) : - CStreamFilter(*EVENTQUEUE, stream, adoptStream), + CStreamFilter(EVENTQUEUE, stream, adoptStream), m_size(0), m_inputShutdown(false) { diff --git a/src/lib/synergy/ProtocolTypes.cpp b/src/lib/synergy/ProtocolTypes.cpp index ebcf48cc..35940f39 100644 --- a/src/lib/synergy/ProtocolTypes.cpp +++ b/src/lib/synergy/ProtocolTypes.cpp @@ -50,6 +50,7 @@ const char* kMsgDGameButtons = "DGBT%1i%2i"; 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* 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 fca16a5e..3ab3a44d 100644 --- a/src/lib/synergy/ProtocolTypes.h +++ b/src/lib/synergy/ProtocolTypes.h @@ -283,6 +283,11 @@ extern const char* kMsgDInfo; // pairs. extern const char* kMsgDSetOptions; +// crypto iv: primary -> secondary +// sends a new iv (initialization vector) to the client for the +// cryptography stream. +extern const char* kMsgDCryptoIv; + // // query codes // diff --git a/src/test/unittests/CMakeLists.txt b/src/test/unittests/CMakeLists.txt index 693befd2..441eb1ac 100644 --- a/src/test/unittests/CMakeLists.txt +++ b/src/test/unittests/CMakeLists.txt @@ -20,6 +20,8 @@ set(h synergy/CMockKeyMap.h client/CMockClient.h io/CMockStream.h + server/CMockServer.h + io/CMockCryptoStream.h ) set(src @@ -29,12 +31,14 @@ set(src synergy/CKeyStateTests.cpp client/CServerProxyTests.cpp synergy/CCryptoStreamTests.cpp + server/CClientProxyTests.cpp ) set(inc ../../lib/arch ../../lib/base ../../lib/client + ../../lib/server ../../lib/common ../../lib/io ../../lib/mt @@ -63,4 +67,4 @@ endif() include_directories(${inc}) add_executable(unittests ${src}) target_link_libraries(unittests - arch base client common io net platform server synergy mt gtest gmock cryptopp ${libs}) + arch base client server common io net platform server synergy mt gtest gmock cryptopp ${libs}) diff --git a/src/test/unittests/client/CMockClient.h b/src/test/unittests/client/CMockClient.h index 0311a1e4..c83f4be0 100644 --- a/src/test/unittests/client/CMockClient.h +++ b/src/test/unittests/client/CMockClient.h @@ -19,6 +19,8 @@ #pragma once #include + +#define TEST_ENV #include "CClient.h" class IEventQueue; @@ -26,6 +28,9 @@ class IEventQueue; class CMockClient : public CClient { public: - CMockClient(IEventQueue& eventQueue) : CClient(eventQueue) { m_mock = true; } + CMockClient() { m_mock = true; } MOCK_METHOD2(mouseMove, void(SInt32, SInt32)); + MOCK_METHOD1(setOptions, void(const COptionsList&)); + MOCK_METHOD0(handshakeComplete, void()); + MOCK_METHOD1(setCryptoIv, void(const UInt8*)); }; diff --git a/src/test/unittests/client/CServerProxyTests.cpp b/src/test/unittests/client/CServerProxyTests.cpp index b37cc0a1..e856c692 100644 --- a/src/test/unittests/client/CServerProxyTests.cpp +++ b/src/test/unittests/client/CServerProxyTests.cpp @@ -16,11 +16,9 @@ * along with this program. If not, see . */ -#include - #define TEST_ENV -#include "Global.h" +#include #include "CServerProxy.h" #include "CMockClient.h" #include "CMockStream.h" @@ -32,60 +30,77 @@ using ::testing::Invoke; using ::testing::NiceMock; using ::testing::AnyNumber; -int streamReads = 0; +const UInt8 mouseMove_bufferLen = 16; +UInt8 mouseMove_buffer[mouseMove_bufferLen]; +UInt32 mouseMove_bufferIndex = 0; +UInt32 mouseMove_mockRead(void* buffer, UInt32 n); -UInt32 -streamRead(void* buffer, UInt32 n); +const UInt8 cryptoIv_bufferLen = 20; +UInt8 cryptoIv_buffer[cryptoIv_bufferLen]; +UInt32 cryptoIv_bufferIndex = 0; +CString cryptoIv_result; +UInt32 cryptoIv_mockRead(void* buffer, UInt32 n); +void cryptoIv_setCryptoIv(const UInt8*); -// TODO: fix linking in windows (works in unix for some reason). -#if 0 -TEST(CServerProxyTests, parseMessage_mouseMove_valuesCorrect) +TEST(CServerProxyTests, mouseMove) { NiceMock eventQueue; - CMockClient client(eventQueue); - CMockStream stream(eventQueue); + NiceMock client; + NiceMock stream; - ON_CALL(stream, read(_, _)).WillByDefault(Invoke(streamRead)); - EXPECT_CALL(stream, read(_, _)).Times(4); - EXPECT_CALL(stream, write(_, _)).Times(1); - EXPECT_CALL(stream, isReady()).Times(1); - EXPECT_CALL(stream, getEventTarget()).Times(AnyNumber()); + ON_CALL(stream, read(_, _)).WillByDefault(Invoke(mouseMove_mockRead)); + + EXPECT_CALL(client, mouseMove(1, 2)).Times(1); + + const char data[] = "DSOP\0\0\0\0DMMV\0\1\0\2"; + memcpy(mouseMove_buffer, data, sizeof(data)); - CServerProxy serverProxy(&client, &stream, eventQueue); - - // skip handshake, go straight to normal parser. - serverProxy.m_parser = &CServerProxy::parseMessage; - - // assert - EXPECT_CALL(client, mouseMove(10, 20)); - - serverProxy.handleData(NULL, NULL); + CServerProxy serverProxy(&client, &stream, &eventQueue); + serverProxy.handleDataForTest(); +} + +TEST(CServerProxyTests, cryptoIv) +{ + NiceMock eventQueue; + NiceMock client; + NiceMock stream; + + ON_CALL(stream, read(_, _)).WillByDefault(Invoke(cryptoIv_mockRead)); + ON_CALL(client, setCryptoIv(_)).WillByDefault(Invoke(cryptoIv_setCryptoIv)); + + const char data[] = "DSOP\0\0\0\0DCIV\0\0\0\4mock"; + memcpy(cryptoIv_buffer, data, sizeof(data)); + + CServerProxy serverProxy(&client, &stream, &eventQueue); + serverProxy.handleDataForTest(); + + EXPECT_EQ("mock", cryptoIv_result); } -#endif UInt32 -streamRead(void* buffer, UInt32 n) +mouseMove_mockRead(void* buffer, UInt32 n) { - streamReads++; - UInt8* code = (UInt8*)buffer; - - if (streamReads == 1) { - code[0] = 'D'; - code[1] = 'M'; - code[2] = 'M'; - code[3] = 'V'; - return 4; + if (mouseMove_bufferIndex >= mouseMove_bufferLen) { + return 0; } - else if (streamReads == 2) { - code[0] = 0; - code[1] = 10; - return 2; - } - else if (streamReads == 3) { - code[0] = 0; - code[1] = 20; - return 2; - } - - return 0; + memcpy(buffer, &mouseMove_buffer[mouseMove_bufferIndex], n); + mouseMove_bufferIndex += n; + return n; +} + +UInt32 +cryptoIv_mockRead(void* buffer, UInt32 n) +{ + if (cryptoIv_bufferIndex >= cryptoIv_bufferLen) { + return 0; + } + memcpy(buffer, &cryptoIv_buffer[cryptoIv_bufferIndex], n); + cryptoIv_bufferIndex += n; + return n; +} + +void +cryptoIv_setCryptoIv(const UInt8* data) +{ + cryptoIv_result = reinterpret_cast(data); } diff --git a/src/test/unittests/io/CMockCryptoStream.h b/src/test/unittests/io/CMockCryptoStream.h new file mode 100644 index 00000000..33a51fdc --- /dev/null +++ b/src/test/unittests/io/CMockCryptoStream.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 +#include "CCryptoStream.h" + +class CMockCryptoStream : public CCryptoStream +{ +public: + CMockCryptoStream(IEventQueue* eventQueue, IStream* stream) : CCryptoStream(eventQueue, stream, false) { } + MOCK_METHOD2(read, UInt32(void*, UInt32)); + MOCK_METHOD2(write, void(const void*, UInt32)); +}; diff --git a/src/test/unittests/io/CMockStream.h b/src/test/unittests/io/CMockStream.h index 9acca308..2de401d3 100644 --- a/src/test/unittests/io/CMockStream.h +++ b/src/test/unittests/io/CMockStream.h @@ -26,13 +26,17 @@ class IEventQueue; class CMockStream : public synergy::IStream { public: - CMockStream(IEventQueue& eventQueue) : IStream(eventQueue) { } + CMockStream() : synergy::IStream(NULL) { } MOCK_METHOD0(close, void()); MOCK_METHOD2(read, UInt32(void*, UInt32)); MOCK_METHOD2(write, void(const void*, UInt32)); MOCK_METHOD0(flush, void()); MOCK_METHOD0(shutdownInput, void()); MOCK_METHOD0(shutdownOutput, void()); + MOCK_METHOD0(getInputReadyEvent, CEvent::Type()); + MOCK_METHOD0(getOutputErrorEvent, CEvent::Type()); + MOCK_METHOD0(getInputShutdownEvent, CEvent::Type()); + MOCK_METHOD0(getOutputShutdownEvent, CEvent::Type()); MOCK_CONST_METHOD0(getEventTarget, void*()); MOCK_CONST_METHOD0(isReady, bool()); MOCK_CONST_METHOD0(getSize, UInt32()); diff --git a/src/test/unittests/server/CClientProxyTests.cpp b/src/test/unittests/server/CClientProxyTests.cpp new file mode 100644 index 00000000..6c1625f1 --- /dev/null +++ b/src/test/unittests/server/CClientProxyTests.cpp @@ -0,0 +1,96 @@ +/* + * 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 "CClientProxy1_4.h" +#include "CMockServer.h" +#include "CMockStream.h" +#include "CMockCryptoStream.h" +#include "CMockEventQueue.h" + +using ::testing::_; +using ::testing::NiceMock; +using ::testing::Invoke; + +const byte g_key[] = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; // +\0, 32-byte/256-bit key. +const byte g_iv[] = "bbbbbbbbbbbbbb"; // +\0, AES block size = 16 + +const UInt8 cryptoIvWrite_bufferLen = 200; +UInt8 cryptoIvWrite_buffer[cryptoIvWrite_bufferLen]; +UInt32 cryptoIvWrite_bufferIndex = 0; + +void +cryptoIv_mockWrite(const void* in, UInt32 n); + +TEST(CClientProxyTests, cryptoIvWrite) +{ + NiceMock eventQueue; + NiceMock innerStream; + NiceMock server; + NiceMock* stream = new NiceMock(&eventQueue, &innerStream); + stream->setKeyWithIv(g_key, sizeof(g_key), g_iv); + + ON_CALL(*stream, write(_, _)).WillByDefault(Invoke(cryptoIv_mockWrite)); + + CClientProxy1_4 clientProxy("stub", stream, &server, &eventQueue); + + // DCIV, then DKDN. + cryptoIvWrite_bufferIndex = 0; + clientProxy.keyDown(1, 2, 3); + EXPECT_EQ('D', cryptoIvWrite_buffer[0]); + EXPECT_EQ('C', cryptoIvWrite_buffer[1]); + EXPECT_EQ('I', cryptoIvWrite_buffer[2]); + EXPECT_EQ('V', cryptoIvWrite_buffer[3]); + EXPECT_EQ('D', cryptoIvWrite_buffer[24]); + EXPECT_EQ('K', cryptoIvWrite_buffer[25]); + EXPECT_EQ('D', cryptoIvWrite_buffer[26]); + EXPECT_EQ('N', cryptoIvWrite_buffer[27]); + + // DCIV, then DKUP. + cryptoIvWrite_bufferIndex = 0; + clientProxy.keyUp(1, 2, 3); + EXPECT_EQ('D', cryptoIvWrite_buffer[0]); + EXPECT_EQ('C', cryptoIvWrite_buffer[1]); + EXPECT_EQ('I', cryptoIvWrite_buffer[2]); + EXPECT_EQ('V', cryptoIvWrite_buffer[3]); + EXPECT_EQ('D', cryptoIvWrite_buffer[24]); + EXPECT_EQ('K', cryptoIvWrite_buffer[25]); + EXPECT_EQ('U', cryptoIvWrite_buffer[26]); + EXPECT_EQ('P', cryptoIvWrite_buffer[27]); + + // DCIV, then DKRP. + cryptoIvWrite_bufferIndex = 0; + clientProxy.keyRepeat(1, 2, 4, 4); + EXPECT_EQ('D', cryptoIvWrite_buffer[0]); + EXPECT_EQ('C', cryptoIvWrite_buffer[1]); + EXPECT_EQ('I', cryptoIvWrite_buffer[2]); + EXPECT_EQ('V', cryptoIvWrite_buffer[3]); + EXPECT_EQ('D', cryptoIvWrite_buffer[24]); + EXPECT_EQ('K', cryptoIvWrite_buffer[25]); + EXPECT_EQ('R', cryptoIvWrite_buffer[26]); + EXPECT_EQ('P', cryptoIvWrite_buffer[27]); +} + +void +cryptoIv_mockWrite(const void* in, UInt32 n) +{ + if (cryptoIvWrite_bufferIndex >= cryptoIvWrite_bufferLen) { + return; + } + memcpy(&cryptoIvWrite_buffer[cryptoIvWrite_bufferIndex], in, n); + cryptoIvWrite_bufferIndex += n; +} diff --git a/src/test/unittests/server/CMockServer.h b/src/test/unittests/server/CMockServer.h new file mode 100644 index 00000000..ba8d5a6b --- /dev/null +++ b/src/test/unittests/server/CMockServer.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 "CServer.h" + +class IEventQueue; + +class CMockServer : public CServer +{ +public: + CMockServer() : CServer() { } +}; diff --git a/src/test/unittests/synergy/CCryptoStreamTests.cpp b/src/test/unittests/synergy/CCryptoStreamTests.cpp index f3eb4a82..94abd179 100644 --- a/src/test/unittests/synergy/CCryptoStreamTests.cpp +++ b/src/test/unittests/synergy/CCryptoStreamTests.cpp @@ -23,6 +23,7 @@ using ::testing::_; using ::testing::Invoke; +using ::testing::NiceMock; using namespace std; @@ -64,17 +65,12 @@ TEST(CCryptoTests, write) buffer[2] = 'D'; buffer[3] = 'N'; - CMockEventQueue eventQueue; - CMockStream innerStream(eventQueue); + NiceMock eventQueue; + NiceMock innerStream; ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write_mockWrite)); - EXPECT_CALL(innerStream, write(_, _)).Times(1); - EXPECT_CALL(innerStream, getEventTarget()).Times(3); - EXPECT_CALL(eventQueue, removeHandlers(_)).Times(1); - EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(1); - EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1); - CCryptoStream cs(eventQueue, &innerStream, false); + CCryptoStream cs(&eventQueue, &innerStream, false); cs.setKeyWithIv(g_key, sizeof(g_key), g_iv); cs.write(buffer, size); @@ -86,17 +82,12 @@ TEST(CCryptoTests, write) TEST(CCryptoTests, read) { - CMockEventQueue eventQueue; - CMockStream innerStream(eventQueue); + NiceMock eventQueue; + NiceMock innerStream; ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(read_mockRead)); - EXPECT_CALL(innerStream, read(_, _)).Times(1); - EXPECT_CALL(innerStream, getEventTarget()).Times(3); - EXPECT_CALL(eventQueue, removeHandlers(_)).Times(1); - EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(1); - EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1); - CCryptoStream cs(eventQueue, &innerStream, false); + CCryptoStream cs(&eventQueue, &innerStream, false); cs.setKeyWithIv(g_key, sizeof(g_key), g_iv); g_read_buffer[0] = 254; @@ -116,19 +107,13 @@ TEST(CCryptoTests, read) TEST(CCryptoTests, write4Read1) { - CMockEventQueue eventQueue; - CMockStream innerStream(eventQueue); + NiceMock eventQueue; + NiceMock innerStream; ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write4Read1_mockWrite)); ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(write4Read1_mockRead)); - EXPECT_CALL(innerStream, write(_, _)).Times(4); - EXPECT_CALL(innerStream, read(_, _)).Times(1); - EXPECT_CALL(innerStream, getEventTarget()).Times(6); - EXPECT_CALL(eventQueue, removeHandlers(_)).Times(2); - EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(2); - EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2); - CCryptoStream cs1(eventQueue, &innerStream, false); + CCryptoStream cs1(&eventQueue, &innerStream, false); cs1.setKeyWithIv(g_key, sizeof(g_key), g_iv); cs1.write("a", 1); @@ -136,7 +121,7 @@ TEST(CCryptoTests, write4Read1) cs1.write("c", 1); cs1.write("d", 1); - CCryptoStream cs2(eventQueue, &innerStream, false); + CCryptoStream cs2(&eventQueue, &innerStream, false); cs2.setKeyWithIv(g_key, sizeof(g_key), g_iv); UInt8 buffer[4]; @@ -150,19 +135,13 @@ TEST(CCryptoTests, write4Read1) TEST(CCryptoTests, write1Read4) { - CMockEventQueue eventQueue; - CMockStream innerStream(eventQueue); + NiceMock eventQueue; + NiceMock innerStream; ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(write1Read4_mockWrite)); ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(write1Read4_mockRead)); - EXPECT_CALL(innerStream, write(_, _)).Times(1); - EXPECT_CALL(innerStream, read(_, _)).Times(4); - EXPECT_CALL(innerStream, getEventTarget()).Times(6); - EXPECT_CALL(eventQueue, removeHandlers(_)).Times(2); - EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(2); - EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2); - CCryptoStream cs1(eventQueue, &innerStream, false); + CCryptoStream cs1(&eventQueue, &innerStream, false); cs1.setKeyWithIv(g_key, sizeof(g_key), g_iv); UInt8 bufferIn[4]; @@ -172,7 +151,7 @@ TEST(CCryptoTests, write1Read4) bufferIn[3] = 'd'; cs1.write(bufferIn, 4); - CCryptoStream cs2(eventQueue, &innerStream, false); + CCryptoStream cs2(&eventQueue, &innerStream, false); cs2.setKeyWithIv(g_key, sizeof(g_key), g_iv); UInt8 bufferOut[4]; @@ -189,22 +168,16 @@ TEST(CCryptoTests, write1Read4) TEST(CCryptoTests, readWriteIvChanged) { - CMockEventQueue eventQueue; - CMockStream innerStream(eventQueue); + NiceMock eventQueue; + NiceMock innerStream; ON_CALL(innerStream, write(_, _)).WillByDefault(Invoke(readWriteIvChanged_mockWrite)); ON_CALL(innerStream, read(_, _)).WillByDefault(Invoke(readWriteIvChanged_mockRead)); - EXPECT_CALL(innerStream, write(_, _)).Times(2); - EXPECT_CALL(innerStream, read(_, _)).Times(2); - EXPECT_CALL(innerStream, getEventTarget()).Times(6); - EXPECT_CALL(eventQueue, removeHandlers(_)).Times(2); - EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(2); - EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2); const byte iv1[] = "bbbbbbbbbbbbbbb"; const byte iv2[] = "ccccccccccccccc"; - CCryptoStream cs1(eventQueue, &innerStream, false); + CCryptoStream cs1(&eventQueue, &innerStream, false); cs1.setKeyWithIv(g_key, sizeof(g_key), iv1); UInt8 bufferIn[4]; @@ -214,7 +187,7 @@ TEST(CCryptoTests, readWriteIvChanged) bufferIn[3] = 'd'; cs1.write(bufferIn, 4); - CCryptoStream cs2(eventQueue, &innerStream, false); + CCryptoStream cs2(&eventQueue, &innerStream, false); cs2.setKeyWithIv(g_key, sizeof(g_key), iv2); UInt8 bufferOut[4]; @@ -296,8 +269,6 @@ readWriteIvChanged_mockRead(void* out, UInt32 n) return n; } -// TODO: macro? - void readWriteIvChangeTrigger_mockWrite(const void* in, UInt32 n) {