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.
This commit is contained in:
parent
6f97f1d186
commit
c368013f13
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -30,11 +30,12 @@
|
|||
#include "CLog.h"
|
||||
#include "IEventQueue.h"
|
||||
#include "TMethodEventJob.h"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include "CArch.h"
|
||||
#include "IPlatformScreen.h"
|
||||
#include "CCryptoStream.h"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
|
||||
//
|
||||
// CClient
|
||||
|
@ -83,6 +84,10 @@ CClient::CClient(IEventQueue* events,
|
|||
getEventTarget(),
|
||||
new TMethodEventJob<CClient>(this,
|
||||
&CClient::handleGameDeviceFeedback));
|
||||
m_events->adoptHandler(m_events->forIScreen().fileChunkSending(),
|
||||
this,
|
||||
new TMethodEventJob<CClient>(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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,6 +105,7 @@ private:
|
|||
void setOptions();
|
||||
void queryInfo();
|
||||
void infoAcknowledgment();
|
||||
void fileChunkReceived();
|
||||
|
||||
private:
|
||||
typedef EResult (CServerProxy::*MessageParser)(const UInt8*);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<CSocketMultiplexer>(
|
||||
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
|
||||
|
|
|
@ -108,8 +108,6 @@ private:
|
|||
CSocketJobs m_socketJobs;
|
||||
CSocketJobMap m_socketJobMap;
|
||||
ISocketMultiplexerJob* m_cursorMark;
|
||||
|
||||
static CSocketMultiplexer* s_instance;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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<CTCPListenSocket>(
|
||||
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<CTCPListenSocket>(
|
||||
this, &CTCPListenSocket::serviceListening,
|
||||
m_socket, true, false));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -63,6 +63,9 @@ public:
|
|||
*/
|
||||
CClientProxy* getNextClient();
|
||||
|
||||
//! Get server which owns this listener
|
||||
CServer* getServer() { return m_server; }
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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<const char*>(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);
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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);
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
/*!
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<CServer>(this,
|
||||
&CServer::handleFakeInputEndEvent));
|
||||
m_events->adoptHandler(m_events->forIScreen().fileChunkSending(),
|
||||
this,
|
||||
new TMethodEventJob<CServer>(this,
|
||||
&CServer::handleFileChunkSendingEvent));
|
||||
|
||||
// add connection
|
||||
addClient(m_primaryClient);
|
||||
|
@ -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<CString>& 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<UInt8*>(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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -35,6 +35,7 @@ class ILogOutputter;
|
|||
class CFileLogOutputter;
|
||||
class CScreen;
|
||||
class IEventQueue;
|
||||
class CSocketMultiplexer;
|
||||
|
||||
typedef IArchTaskBarReceiver* (*CreateTaskBarReceiverFunc)(const CBufferedLogOutputter*, IEventQueue* events);
|
||||
|
||||
|
@ -97,6 +98,9 @@ public:
|
|||
|
||||
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."
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IInterface.h"
|
||||
|
||||
class INode : IInterface {
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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<CIpcTests>(
|
||||
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<CIpcTests>(
|
||||
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<CIpcTests>(
|
||||
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<CIpcTests>(
|
||||
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<CIpcCommandMessage*>(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<CIpcLogLineMessage*>(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<CIpcTests>(
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -14,9 +14,16 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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})
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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<CTestEventQueue>(
|
||||
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();
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
};
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#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<CMockScreen> serverScreen;
|
||||
NiceMock<CMockPrimaryClient> primaryClient;
|
||||
NiceMock<CMockConfig> serverConfig;
|
||||
NiceMock<CMockInputFilter> serverInputFilter;
|
||||
|
||||
m_events.adoptHandler(
|
||||
m_events.forCClientListener().connected(), &listener,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
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<CMockScreen> 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<NetworkTests>(
|
||||
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<CClientListener*>(vlistener);
|
||||
CServer* server = listener->getServer();
|
||||
|
||||
CClientProxy* client = listener->getNextClient();
|
||||
if (client == NULL) {
|
||||
throw std::exception("client is null");
|
||||
}
|
||||
|
||||
CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client);
|
||||
server->adoptClient(bcp);
|
||||
server->setActive(bcp);
|
||||
|
||||
sendData(server);
|
||||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*)
|
||||
{
|
||||
CClient* client = reinterpret_cast<CClient*>(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;
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
};
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#define TEST_ENV
|
||||
#include "CConfig.h"
|
||||
|
||||
class CMockConfig : public CConfig
|
||||
{
|
||||
public:
|
||||
CMockConfig() : CConfig() { }
|
||||
MOCK_METHOD0(getInputFilter, CInputFilter*());
|
||||
MOCK_CONST_METHOD1(isScreen, bool(const CString&));
|
||||
};
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#define TEST_ENV
|
||||
#include "CInputFilter.h"
|
||||
|
||||
class CMockInputFilter : public CInputFilter
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD1(setPrimaryClient, void(CPrimaryClient*));
|
||||
};
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#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));
|
||||
};
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
|
||||
#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());
|
||||
};
|
Loading…
Reference in New Issue