Patch by Jerry:

- Fixed line endings
- Integ test for file transfer
- Fixed crashed problem when log info is larger than 2048 bytes
- Fixed compile error caused by std exception (by Feng ye)
- Fixed include path on Mac and linux (by Feng ye)
This commit is contained in:
Nick Bolton 2013-07-24 16:41:12 +00:00
parent c368013f13
commit 394ece004a
72 changed files with 3884 additions and 3127 deletions

View File

@ -178,7 +178,7 @@ CLog::print(const char* file, int line, const char* fmt, ...)
// do not prefix time and file for kPRINT (CLOG_PRINT) // do not prefix time and file for kPRINT (CLOG_PRINT)
if (priority != kPRINT) { if (priority != kPRINT) {
char message[2048]; char message[kLogMessageLength];
#ifndef NDEBUG #ifndef NDEBUG
struct tm *tm; struct tm *tm;

View File

@ -137,6 +137,8 @@ private:
int m_maxPriority; int m_maxPriority;
}; };
const UInt16 kLogMessageLength = 2048;
/*! /*!
\def LOG(arg) \def LOG(arg)
Write to the log. Because macros cannot accept variable arguments, this Write to the log. Because macros cannot accept variable arguments, this

View File

@ -33,14 +33,20 @@
#include "CArch.h" #include "CArch.h"
#include "IPlatformScreen.h" #include "IPlatformScreen.h"
#include "CCryptoStream.h" #include "CCryptoStream.h"
#include "CThread.h"
#include "TMethodJob.h"
#include "CFileChunker.h"
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include <sstream> #include <sstream>
#include <fstream>
// //
// CClient // CClient
// //
const size_t CClient::m_chunkSize = 1024 * 512; // 512kb
CClient::CClient(IEventQueue* events, CClient::CClient(IEventQueue* events,
const CString& name, const CNetworkAddress& address, const CString& name, const CNetworkAddress& address,
ISocketFactory* socketFactory, ISocketFactory* socketFactory,
@ -438,6 +444,17 @@ CClient::sendConnectionFailedEvent(const char* msg)
m_events->addEvent(event); m_events->addEvent(event);
} }
void
CClient::sendFileChunk(const void* data)
{
CFileChunker::CFileChunk* fileChunk = reinterpret_cast<CFileChunker::CFileChunk*>(const_cast<void*>(data));
LOG((CLOG_DEBUG1 "sendFileChunk"));
assert(m_server != NULL);
// relay
m_server->fileChunkSending(fileChunk->m_chunk[0], &(fileChunk->m_chunk[1]), fileChunk->m_dataSize);
}
void void
CClient::setupConnecting() CClient::setupConnecting()
{ {
@ -737,6 +754,7 @@ CClient::handleGameDeviceFeedback(const CEvent& event, void*)
void void
CClient::handleFileChunkSending(const CEvent& event, void*) CClient::handleFileChunkSending(const CEvent& event, void*)
{ {
sendFileChunk(event.getData());
} }
void void
@ -763,3 +781,24 @@ CClient::isReceivedFileSizeValid()
{ {
return m_expectedFileSize == m_receivedFileData.size(); return m_expectedFileSize == m_receivedFileData.size();
} }
void
CClient::sendFileToServer(const char* filename)
{
CThread* thread = new CThread(
new TMethodJob<CClient>(
this, &CClient::sendFileThread,
reinterpret_cast<void*>(const_cast<char*>(filename))));
}
void
CClient::sendFileThread(void* filename)
{
try {
char* name = reinterpret_cast<char*>(filename);
CFileChunker::sendFileChunks(name, m_events, this);
}
catch (std::runtime_error error) {
LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
}
}

View File

@ -101,8 +101,8 @@ public:
//! Received a chunk of file data //! Received a chunk of file data
void fileChunkReceived(CString data); void fileChunkReceived(CString data);
//! Return true if recieved file size is valid //! Create a new thread and use it to send file to Server
bool isReceivedFileSizeValid(); void sendFileToServer(const char* filename);
//@} //@}
//! @name accessors //! @name accessors
@ -128,6 +128,9 @@ public:
*/ */
CNetworkAddress getServerAddress() const; CNetworkAddress getServerAddress() const;
//! Return true if recieved file size is valid
bool isReceivedFileSizeValid();
//@} //@}
// IScreen overrides // IScreen overrides
@ -167,6 +170,8 @@ private:
void sendClipboard(ClipboardID); void sendClipboard(ClipboardID);
void sendEvent(CEvent::Type, void*); void sendEvent(CEvent::Type, void*);
void sendConnectionFailedEvent(const char* msg); void sendConnectionFailedEvent(const char* msg);
void sendFileChunk(const void* data);
void sendFileThread(void*);
void setupConnecting(); void setupConnecting();
void setupConnection(); void setupConnection();
void setupScreen(); void setupScreen();
@ -214,6 +219,7 @@ private:
CCryptoOptions m_crypto; CCryptoOptions m_crypto;
std::size_t m_expectedFileSize; std::size_t m_expectedFileSize;
CString m_receivedFileData; CString m_receivedFileData;
static const size_t m_chunkSize;
}; };
#endif #endif

View File

@ -935,7 +935,8 @@ CServerProxy::infoAcknowledgment()
m_ignoreMouse = false; m_ignoreMouse = false;
} }
void CServerProxy::fileChunkReceived() void
CServerProxy::fileChunkReceived()
{ {
// parse // parse
UInt8 mark; UInt8 mark;
@ -943,20 +944,42 @@ void CServerProxy::fileChunkReceived()
CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content); CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content);
switch (mark) { switch (mark) {
case '0': case kFileStart:
LOG((CLOG_DEBUG2 "recv file data: file size = %s", content)); LOG((CLOG_DEBUG2 "recv file data from server: size=%s", content.c_str()));
m_client->clearReceivedFileData(); m_client->clearReceivedFileData();
m_client->setExpectedFileSize(content); m_client->setExpectedFileSize(content);
break; break;
case '1': case kFileChunk:
LOG((CLOG_DEBUG2 "recv file data: chunck size = %i", content.size())); LOG((CLOG_DEBUG2 "recv file data from server: size=%i", content.size()));
m_client->fileChunkReceived(content); m_client->fileChunkReceived(content);
break; break;
case '2': case kFileEnd:
LOG((CLOG_DEBUG2 "file data transfer finished")); LOG((CLOG_DEBUG2 "file data transfer finished"));
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), m_client)); m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), m_client));
break; break;
} }
} }
void
CServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{
CString chunk(data, dataSize);
switch (mark) {
case kFileStart:
LOG((CLOG_DEBUG2 "file sending start: size=%s", data));
break;
case kFileChunk:
LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size()));
break;
case kFileEnd:
LOG((CLOG_DEBUG2 "file sending finished"));
break;
}
CProtocolUtil::writef(m_stream, kMsgDFileTransfer, mark, &chunk);
}

View File

@ -56,6 +56,14 @@ public:
//@} //@}
//! @file transfer
//@{
//! sending file chunk to server
void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
//@}
#ifdef TEST_ENV #ifdef TEST_ENV
void handleDataForTest() { handleData(CEvent(), NULL); } void handleDataForTest() { handleData(CEvent(), NULL); }
#endif #endif

View File

@ -83,7 +83,7 @@ public:
virtual void screensaver(bool activate) = 0; virtual void screensaver(bool activate) = 0;
virtual void resetOptions() = 0; virtual void resetOptions() = 0;
virtual void setOptions(const COptionsList& options) = 0; virtual void setOptions(const COptionsList& options) = 0;
virtual void fileChunkSending(UInt8 mark, const UInt8* data) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0;
virtual CString getName() const; virtual CString getName() const;
private: private:

View File

@ -89,7 +89,7 @@ public:
virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2) = 0; virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2) = 0;
virtual void gameDeviceTimingReq() = 0; virtual void gameDeviceTimingReq() = 0;
virtual void cryptoIv(const UInt8* iv) = 0; virtual void cryptoIv(const UInt8* iv) = 0;
virtual void fileChunkSending(UInt8 mark, const UInt8* data) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0;
private: private:
synergy::IStream* m_stream; synergy::IStream* m_stream;

View File

@ -394,7 +394,7 @@ CClientProxy1_0::cryptoIv(const UInt8* iv)
} }
void void
CClientProxy1_0::fileChunkSending(UInt8 mark, const UInt8* iv) CClientProxy1_0::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {
// ignore -- not supported in protocol 1.0 // ignore -- not supported in protocol 1.0
LOG((CLOG_DEBUG "fileChunkSending not supported")); LOG((CLOG_DEBUG "fileChunkSending not supported"));

View File

@ -64,7 +64,7 @@ public:
virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2); virtual void gameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2);
virtual void gameDeviceTimingReq(); virtual void gameDeviceTimingReq();
virtual void cryptoIv(const UInt8* iv); virtual void cryptoIv(const UInt8* iv);
virtual void fileChunkSending(UInt8 mark, const UInt8* data); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
protected: protected:
virtual bool parseHandshakeMessage(const UInt8* code); virtual bool parseHandshakeMessage(const UInt8* code);

View File

@ -42,7 +42,6 @@ protected:
private: private:
void handleKeepAlive(const CEvent&, void*); void handleKeepAlive(const CEvent&, void*);
private: private:
double m_keepAliveRate; double m_keepAliveRate;
CEventQueueTimer* m_keepAliveTimer; CEventQueueTimer* m_keepAliveTimer;

View File

@ -29,6 +29,14 @@ public:
CClientProxy1_4(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events); CClientProxy1_4(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events);
~CClientProxy1_4(); ~CClientProxy1_4();
//! @name accessors
//@{
//! get server pointer
CServer* getServer() { return m_server; }
//@}
// IClient overrides // IClient overrides
virtual void gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons); virtual void gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons);
virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2); virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2);

View File

@ -19,13 +19,15 @@
#include "CProtocolUtil.h" #include "CProtocolUtil.h"
#include "CLog.h" #include "CLog.h"
#include "IStream.h" #include "IStream.h"
#include "CServer.h"
// //
// CClientProxy1_5 // CClientProxy1_5
// //
CClientProxy1_5::CClientProxy1_5(const CString& name, synergy::IStream* stream, CServer* server, IEventQueue* events) : CClientProxy1_5::CClientProxy1_5(const CString& name, synergy::IStream* stream, CServer* server, IEventQueue* events) :
CClientProxy1_4(name, stream, server, events) CClientProxy1_4(name, stream, server, events),
m_events(events)
{ {
} }
@ -34,23 +36,64 @@ CClientProxy1_5::~CClientProxy1_5()
} }
void void
CClientProxy1_5::fileChunkSending(UInt8 mark, const UInt8* data) CClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {
CString chunk(reinterpret_cast<const char*>(data)); CString chunk(data, dataSize);
switch (mark) { switch (mark) {
case '0': case kFileStart:
LOG((CLOG_DEBUG2 "file sending start: file size = %s", data)); LOG((CLOG_DEBUG2 "file sending start: size=%s", data));
break; break;
case '1': case kFileChunk:
LOG((CLOG_DEBUG2 "file chunk sending: %s", data)); LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size()));
break; break;
case '2': case kFileEnd:
LOG((CLOG_DEBUG2 "file sending finished")); LOG((CLOG_DEBUG2 "file sending finished"));
break; break;
} }
CProtocolUtil::writef(getStream(), kMsgDFileTransfer, mark, &chunk); CProtocolUtil::writef(getStream(), kMsgDFileTransfer, mark, &chunk);
} }
bool
CClientProxy1_5::parseMessage(const UInt8* code)
{
if (memcmp(code, kMsgDFileTransfer, 4) == 0) {
fileChunkReceived();
}
else {
return CClientProxy1_4::parseMessage(code);
}
return true;
}
void
CClientProxy1_5::fileChunkReceived()
{
// parse
UInt8 mark;
CString content;
CProtocolUtil::readf(getStream(), kMsgDFileTransfer + 4, &mark, &content);
CServer* server = getServer();
switch (mark) {
case kFileStart:
LOG((CLOG_DEBUG2 "recv file data from client: file size=%s", content.c_str()));
server->clearReceivedFileData();
server->setExpectedFileSize(content);
break;
case kFileChunk:
LOG((CLOG_DEBUG2 "recv file data from client: chunck size=%i", content.size()));
server->fileChunkReceived(content);
break;
case kFileEnd:
LOG((CLOG_DEBUG2 "file data transfer finished"));
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), server));
break;
}
}

View File

@ -28,5 +28,10 @@ public:
CClientProxy1_5(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events); CClientProxy1_5(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events);
~CClientProxy1_5(); ~CClientProxy1_5();
virtual void fileChunkSending(UInt8 mark, const UInt8* data); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
virtual bool parseMessage(const UInt8* code);
void fileChunkReceived();
private:
IEventQueue* m_events;
}; };

View File

@ -274,7 +274,7 @@ CPrimaryClient::screensaver(bool)
} }
void void
CPrimaryClient::fileChunkSending(UInt8 mark, const UInt8* data) CPrimaryClient::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
{ {
// ignore // ignore
} }

View File

@ -148,7 +148,7 @@ public:
virtual void screensaver(bool activate); virtual void screensaver(bool activate);
virtual void resetOptions(); virtual void resetOptions();
virtual void setOptions(const COptionsList& options); virtual void setOptions(const COptionsList& options);
virtual void fileChunkSending(UInt8 mark, const UInt8* data); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
private: private:
CScreen* m_screen; CScreen* m_screen;

View File

@ -33,14 +33,22 @@
#include "TMethodEventJob.h" #include "TMethodEventJob.h"
#include "CArch.h" #include "CArch.h"
#include "CKeyState.h" #include "CKeyState.h"
#include "CScreen.h"
#include "CThread.h"
#include "TMethodJob.h"
#include "CFileChunker.h"
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#include "CScreen.h" #include <sstream>
#include <fstream>
#include <sstream>
// //
// CServer // CServer
// //
const size_t CServer::m_chunkSize = 1024 * 512; // 512kb
CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen, IEventQueue* events) : CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen, IEventQueue* events) :
m_events(events), m_events(events),
m_mock(false), m_mock(false),
@ -177,6 +185,10 @@ CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen
this, this,
new TMethodEventJob<CServer>(this, new TMethodEventJob<CServer>(this,
&CServer::handleFileChunkSendingEvent)); &CServer::handleFileChunkSendingEvent));
m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(),
this,
new TMethodEventJob<CServer>(this,
&CServer::handleFileRecieveCompleteEvent));
// add connection // add connection
addClient(m_primaryClient); addClient(m_primaryClient);
@ -1516,8 +1528,13 @@ CServer::handleFakeInputEndEvent(const CEvent&, void*)
void void
CServer::handleFileChunkSendingEvent(const CEvent& event, void*) CServer::handleFileChunkSendingEvent(const CEvent& event, void*)
{ {
UInt8* data = reinterpret_cast<UInt8*>(event.getData()); onFileChunkSending(event.getData());
onFileChunkSending(data); }
void
CServer::handleFileRecieveCompleteEvent(const CEvent& event, void*)
{
onFileRecieveComplete();
} }
void void
@ -1981,13 +1998,32 @@ CServer::onGameDeviceTimingReq()
} }
void void
CServer::onFileChunkSending(const UInt8* data) CServer::onFileChunkSending(const void* data)
{ {
CFileChunker::CFileChunk* fileChunk = reinterpret_cast<CFileChunker::CFileChunk*>(const_cast<void*>(data));
LOG((CLOG_DEBUG1 "onFileChunkSending")); LOG((CLOG_DEBUG1 "onFileChunkSending"));
assert(m_active != NULL); assert(m_active != NULL);
// relay // relay
m_active->fileChunkSending(data[0], &data[1]); m_active->fileChunkSending(fileChunk->m_chunk[0], &(fileChunk->m_chunk[1]), fileChunk->m_dataSize);
}
void
CServer::onFileRecieveComplete()
{
if (isReceivedFileSizeValid()) {
if (!m_fileTransferDes.empty()) {
std::fstream file;
file.open(m_fileTransferDes.c_str(), std::ios::out | std::ios::binary);
if (!file.is_open()) {
// TODO: file open failed
}
file.write(m_receivedFileData.c_str(), m_receivedFileData.size());
file.close();
}
}
} }
bool bool
@ -2260,3 +2296,49 @@ CServer::CKeyboardBroadcastInfo::alloc(State state, const CString& screens)
strcpy(info->m_screens, screens.c_str()); strcpy(info->m_screens, screens.c_str());
return info; return info;
} }
void
CServer::clearReceivedFileData()
{
m_receivedFileData.clear();
}
void
CServer::setExpectedFileSize(CString data)
{
std::istringstream iss(data);
iss >> m_expectedFileSize;
}
void
CServer::fileChunkReceived(CString data)
{
m_receivedFileData += data;
}
bool
CServer::isReceivedFileSizeValid()
{
return m_expectedFileSize == m_receivedFileData.size();
}
void
CServer::sendFileToClient(const char* filename)
{
CThread* thread = new CThread(
new TMethodJob<CServer>(
this, &CServer::sendFileThread,
reinterpret_cast<void*>(const_cast<char*>(filename))));
}
void
CServer::sendFileThread(void* filename)
{
try {
char* name = reinterpret_cast<char*>(filename);
CFileChunker::sendFileChunks(name, m_events, this);
}
catch (std::runtime_error error) {
LOG((CLOG_ERR "failed sending file chunks: %s", error.what()));
}
}

View File

@ -144,6 +144,21 @@ public:
//! Notify of game device feedback //! Notify of game device feedback
void gameDeviceFeedback(GameDeviceID id, UInt16 m1, UInt16 m2); void gameDeviceFeedback(GameDeviceID id, UInt16 m1, UInt16 m2);
//! Clears the file buffer
void clearReceivedFileData();
//! Set the expected size of receiving file
void setExpectedFileSize(CString data);
//! Set
void setFileTransferDes(CString& des) { m_fileTransferDes = des; }
//! Received a chunk of file data
void fileChunkReceived(CString data);
//! Create a new thread and use it to send file to client
void sendFileToClient(const char* filename);
//@} //@}
//! @name accessors //! @name accessors
//@{ //@{
@ -160,6 +175,9 @@ public:
*/ */
void getClients(std::vector<CString>& list) const; void getClients(std::vector<CString>& list) const;
//! Return true if recieved file size is valid
bool isReceivedFileSizeValid();
//@} //@}
private: private:
@ -299,6 +317,7 @@ private:
void handleFakeInputBeginEvent(const CEvent&, void*); void handleFakeInputBeginEvent(const CEvent&, void*);
void handleFakeInputEndEvent(const CEvent&, void*); void handleFakeInputEndEvent(const CEvent&, void*);
void handleFileChunkSendingEvent(const CEvent&, void*); void handleFileChunkSendingEvent(const CEvent&, void*);
void handleFileRecieveCompleteEvent(const CEvent&, void*);
// event processing // event processing
void onClipboardChanged(CBaseClientProxy* sender, void onClipboardChanged(CBaseClientProxy* sender,
@ -318,7 +337,8 @@ private:
void onGameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2); void onGameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2);
void onGameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2); void onGameDeviceTriggers(GameDeviceID id, UInt8 t1, UInt8 t2);
void onGameDeviceTimingReq(); void onGameDeviceTimingReq();
void onFileChunkSending(const UInt8* data); void onFileChunkSending(const void* data);
void onFileRecieveComplete();
// add client to list and attach event handlers for client // add client to list and attach event handlers for client
bool addClient(CBaseClientProxy*); bool addClient(CBaseClientProxy*);
@ -343,6 +363,9 @@ private:
// force the cursor off of \p client // force the cursor off of \p client
void forceLeaveClient(CBaseClientProxy* client); void forceLeaveClient(CBaseClientProxy* client);
// thread funciton for sending file
void sendFileThread(void*);
public: public:
bool m_mock; bool m_mock;
@ -438,6 +461,13 @@ private:
CScreen* m_screen; CScreen* m_screen;
IEventQueue* m_events; IEventQueue* m_events;
// file transfer
size_t m_expectedFileSize;
CString m_receivedFileData;
static const size_t m_chunkSize;
CString m_fileTransferSrc;
CString m_fileTransferDes;
}; };
#endif #endif

View File

@ -171,6 +171,14 @@ CApp::parseArg(const int& argc, const char* const* argv, int& i)
argsBase().m_crypto.setMode(argv[++i]); argsBase().m_crypto.setMode(argv[++i]);
} }
else if (isArg(i, argc, argv, NULL, "--filetransfer-src")) {
m_fileTransferSrc = argv[++i];
}
else if (isArg(i, argc, argv, NULL, "--filetransfer-des")) {
m_fileTransferDes = argv[++i];
}
else { else {
// option not supported here // option not supported here
return false; return false;

View File

@ -101,6 +101,9 @@ public:
void setSocketMultiplexer(CSocketMultiplexer* sm) { m_socketMultiplexer = sm; } void setSocketMultiplexer(CSocketMultiplexer* sm) { m_socketMultiplexer = sm; }
CSocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; } CSocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; }
CString& getFileTransferSrc() { return m_fileTransferSrc; }
CString& getFileTransferDes() { return m_fileTransferDes; }
private: private:
void handleIpcMessage(const CEvent&, void*); void handleIpcMessage(const CEvent&, void*);
@ -122,6 +125,8 @@ private:
CIpcClient* m_ipcClient; CIpcClient* m_ipcClient;
IEventQueue* m_events; IEventQueue* m_events;
CSocketMultiplexer* m_socketMultiplexer; CSocketMultiplexer* m_socketMultiplexer;
CString m_fileTransferSrc;
CString m_fileTransferDes;
}; };
#define BYE "\nTry `%s --help' for more information." #define BYE "\nTry `%s --help' for more information."

View File

@ -349,6 +349,14 @@ CClientApp::handleClientConnected(const CEvent&, void*)
LOG((CLOG_NOTE "connected to server")); LOG((CLOG_NOTE "connected to server"));
resetRestartTimeout(); resetRestartTimeout();
updateStatus(); updateStatus();
/*
// TODO: remove testing code for relase
CString fileFullDir = getFileTransferSrc();
if (!fileFullDir.empty()) {
s_client->sendFileToServer(getFileTransferSrc().c_str());
}
*/
} }
@ -473,6 +481,7 @@ CClientApp::startClient()
#endif #endif
s_client->connect(); s_client->connect();
updateStatus(); updateStatus();
return true; return true;
} }

View File

@ -0,0 +1,100 @@
/*
* 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 "CFileChunker.h"
#include "BasicTypes.h"
#include "ProtocolTypes.h"
#include "CEvent.h"
#include "IEventQueue.h"
#include "CEventTypes.h"
#include "CLOG.h"
#include <fstream>
#include <sstream>
using namespace std;
const size_t CFileChunker::m_chunkSize = 512 * 1024; // 512kb
void
CFileChunker::sendFileChunks(char* filename, IEventQueue* events, void* eventTarget)
{
std::fstream file(reinterpret_cast<char*>(filename), std::ios::in | std::ios::binary);
if (!file.is_open()) {
throw runtime_error("failed to open file");
}
// check file size
file.seekg (0, std::ios::end);
size_t size = (size_t)file.tellg();
// send first message (file size)
CString fileSize = intToString(size);
UInt32 sizeLength = fileSize.size();
CFileChunk* sizeMessage = new CFileChunk(sizeLength + 2);
char* chunkData = sizeMessage->m_chunk;
chunkData[0] = kFileStart;
memcpy(&chunkData[1], fileSize.c_str(), sizeLength);
chunkData[sizeLength + 1] = '\0';
events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, sizeMessage));
// send chunk messages with a fixed chunk size
size_t sentLength = 0;
size_t chunkSize = m_chunkSize;
file.seekg (0, std::ios::beg);
while (true) {
// make sure we don't read too much from the mock data.
if (sentLength + chunkSize > size) {
chunkSize = size - sentLength;
}
// for fileChunk->m_chunk, the first byte is the chunk mark, last is \0
CFileChunk* fileChunk = new CFileChunk(chunkSize + 2);
char* chunkData = fileChunk->m_chunk;
chunkData[0] = kFileChunk;
file.read(&chunkData[1], chunkSize);
chunkData[chunkSize + 1] = '\0';
events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, fileChunk));
sentLength += chunkSize;
file.seekg (sentLength, std::ios::beg);
if (sentLength == size) {
break;
}
}
// send last message
CFileChunk* transferFinished = new CFileChunk(2);
chunkData = transferFinished->m_chunk;
chunkData[0] = kFileEnd;
chunkData[1] = '\0';
events->addEvent(CEvent(events->forIScreen().fileChunkSending(), eventTarget, transferFinished));
file.close();
}
CString
CFileChunker::intToString(size_t i)
{
stringstream ss;
ss << i;
return ss.str();
}

View File

@ -0,0 +1,46 @@
/*
* 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 "CString.h"
class IEventQueue;
class CFileChunker {
public:
//! FileChunk data
class CFileChunk {
public:
CFileChunk(size_t chunkSize) : m_dataSize(chunkSize - 2)
{
m_chunk = new char[chunkSize];
}
~CFileChunk() { delete[] m_chunk; }
public:
const size_t m_dataSize;
char* m_chunk;
};
static void sendFileChunks(char* filename, IEventQueue* events, void* eventTarget);
static CString intToString(size_t i);
private:
static const size_t m_chunkSize;
};

View File

@ -49,6 +49,7 @@ set(inc
CArgsBase.h CArgsBase.h
IAppUtil.h IAppUtil.h
CEventGameDevice.h CEventGameDevice.h
CFileChunker.h
) )
set(src set(src
@ -77,6 +78,7 @@ set(src
CArgsBase.cpp CArgsBase.cpp
CEventGameDevice.cpp CEventGameDevice.cpp
CGameDevice.cpp CGameDevice.cpp
CFileChunker.cpp
) )
if (WIN32) if (WIN32)

View File

@ -228,7 +228,12 @@ CProtocolUtil::vreadf(synergy::IStream* stream, const char* fmt, va_list args)
} }
throw; throw;
} }
// don't cause buffer overrun, using +100 chars in case
// someone modifies this log message in future.
if (len + 100 < kLogMessageLength) {
LOG((CLOG_DEBUG2 "readf: read %d byte string: %.*s", len, len, sBuffer)); LOG((CLOG_DEBUG2 "readf: read %d byte string: %.*s", len, len, sBuffer));
}
// save the data // save the data
CString* dst = va_arg(args, CString*); CString* dst = va_arg(args, CString*);

View File

@ -688,7 +688,7 @@ CServer*
CServerApp::openServer(CConfig& config, CPrimaryClient* primaryClient) CServerApp::openServer(CConfig& config, CPrimaryClient* primaryClient)
{ {
CServer* server = new CServer(config, primaryClient, s_serverScreen, m_events); CServer* server = new CServer(config, primaryClient, s_serverScreen, m_events);
server->setFileTransferDes(getFileTransferDes());
try { try {
m_events->adoptHandler( m_events->adoptHandler(
m_events->forCServer().disconnected(), server, m_events->forCServer().disconnected(), server,

View File

@ -68,6 +68,13 @@ enum EDirectionMask {
kBottomMask = 1 << kBottom kBottomMask = 1 << kBottom
}; };
// file transfer constants
enum EFileTransfer {
kFileStart = 1,
kFileChunk = 2,
kFileEnd = 3
};
// //
// message codes (trailing NUL is not part of code). in comments, $n // message codes (trailing NUL is not part of code). in comments, $n

View File

@ -19,6 +19,7 @@
#include "CLog.h" #include "CLog.h"
#include "TMethodEventJob.h" #include "TMethodEventJob.h"
#include "CSimpleEventQueueBuffer.h" #include "CSimpleEventQueueBuffer.h"
#include <stdexcept>
void void
CTestEventQueue::raiseQuitEvent() CTestEventQueue::raiseQuitEvent()
@ -47,6 +48,5 @@ CTestEventQueue::cleanupQuitTimeout()
void void
CTestEventQueue::handleQuitTimeout(const CEvent&, void* vclient) CTestEventQueue::handleQuitTimeout(const CEvent&, void* vclient)
{ {
LOG((CLOG_ERR "timeout")); throw std::runtime_error("test event queue timeout");
raiseQuitEvent();
} }

View File

@ -16,8 +16,11 @@
*/ */
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <iostream> #include <stdexcept>
#include <sstream>
#include <fstream> #include <fstream>
#include <iostream>
#include <stdio.h>
#define TEST_ENV #define TEST_ENV
@ -33,13 +36,14 @@
#include "CTCPSocketFactory.h" #include "CTCPSocketFactory.h"
#include "CCryptoOptions.h" #include "CCryptoOptions.h"
#include "CSocketMultiplexer.h" #include "CSocketMultiplexer.h"
#include "CMSWindowsScreen.h"
#include "CGameDevice.h"
#include "CThread.h"
#include "TMethodJob.h"
#include "CTestEventQueue.h" #include "CTestEventQueue.h"
#include "server/CMockInputFilter.h" #include "server/CMockInputFilter.h"
#include "TMethodJob.h"
#include "CThread.h"
#include "CFileChunker.h"
using namespace std;
using ::testing::_; using ::testing::_;
using ::testing::NiceMock; using ::testing::NiceMock;
using ::testing::Return; using ::testing::Return;
@ -48,27 +52,58 @@ using ::testing::Invoke;
#define TEST_PORT 24803 #define TEST_PORT 24803
#define TEST_HOST "localhost" #define TEST_HOST "localhost"
const int klargeDataSize = 512; const size_t kMockDataSize = 1024 * 1024 * 10; // 10MB
char g_largeData[klargeDataSize] = "large data:head.1221412312341244213123fdsfasdawdwadwadacwdd.12321412312341244213123fdsfasdawdwadwadacwdawddawdwacawdawd232141231awddawdwacawdawd2321412312341244213123fdsfasdawdwadacwdawddawdwacawdtrtetawdawdwaewe1213412321412312341244213123fdsfasdawdwadacwdawddawdwacawdawdawdwaewe121341awdwaewedacwdawddawdwacawdawd2321412312341244213123fdsfasdawdwadacwdawddawdwacawdtrtetawdawdwaewe1213412321412312341244213123fdsfasdawdwadacwdawddawdwacawdawdawdwaewe121341awdwaewe12134123njk1u31i2nm3e123hu23oi132213njk.tail"; const UInt16 kMockDataChunkIncrement = 1024; // 1KB
const char* kMockFilename = "NetworkTests.mock";
const size_t kMockFileSize = 1024 * 1024 * 10; // 10MB
void sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h); void getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h);
void sendFileToClient_getCursorPos(SInt32& x, SInt32& y); void getCursorPos(SInt32& x, SInt32& y);
CString intToString(size_t i);
UInt8* newMockData(size_t size);
void createFile(fstream& file, const char* filename, size_t size);
class NetworkTests : public ::testing::Test class NetworkTests : public ::testing::Test
{ {
public: public:
NetworkTests() { } NetworkTests() :
m_mockData(NULL),
m_mockDataSize(0),
m_mockFileSize(0)
{
m_mockData = newMockData(kMockDataSize);
createFile(m_mockFile, kMockFilename, kMockFileSize);
}
void sendData(CServer* server); ~NetworkTests()
{
remove(kMockFilename);
delete[] m_mockData;
}
void sendFileToClient_handleClientConnected(const CEvent&, void* vlistener); void sendMockData(void* eventTarget);
void sendFileToClient_fileRecieveComplete(const CEvent&, void*);
void sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener);
void sendToClient_mockData_fileRecieveComplete(const CEvent&, void*);
void sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener);
void sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*);
void sendToServer_mockData_handleClientConnected(const CEvent&, void* vlistener);
void sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*);
void sendToServer_mockFile_handleClientConnected(const CEvent&, void* vlistener);
void sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*);
public: public:
CTestEventQueue m_events; CTestEventQueue m_events;
UInt8* m_mockData;
size_t m_mockDataSize;
fstream m_mockFile;
size_t m_mockFileSize;
}; };
TEST_F(NetworkTests, sendFileToClient) TEST_F(NetworkTests, sendToClient_mockData)
{ {
// server and client // server and client
CNetworkAddress serverAddress(TEST_HOST, TEST_PORT); CNetworkAddress serverAddress(TEST_HOST, TEST_PORT);
@ -88,7 +123,7 @@ TEST_F(NetworkTests, sendFileToClient)
m_events.adoptHandler( m_events.adoptHandler(
m_events.forCClientListener().connected(), &listener, m_events.forCClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendFileToClient_handleClientConnected, &listener)); this, &NetworkTests::sendToClient_mockData_handleClientConnected, &listener));
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
@ -102,43 +137,196 @@ TEST_F(NetworkTests, sendFileToClient)
CSocketMultiplexer clientSocketMultiplexer; CSocketMultiplexer clientSocketMultiplexer;
CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer); CTCPSocketFactory* clientSocketFactory = new CTCPSocketFactory(&m_events, &clientSocketMultiplexer);
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(sendFileToClient_getShape)); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(sendFileToClient_getCursorPos)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions); CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler( m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &client, m_events.forIScreen().fileRecieveComplete(), &client,
new TMethodEventJob<NetworkTests>( new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendFileToClient_fileRecieveComplete)); this, &NetworkTests::sendToClient_mockData_fileRecieveComplete));
client.connect(); client.connect();
m_events.initQuitTimeout(10); m_events.initQuitTimeout(5);
m_events.loop();
m_events.cleanupQuitTimeout();
}
TEST_F(NetworkTests, sendToClient_mockFile)
{
// 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::sendToClient_mockFile_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(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &client,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToClient_mockFile_fileRecieveComplete));
client.connect();
m_events.initQuitTimeout(5);
m_events.loop();
m_events.cleanupQuitTimeout();
}
TEST_F(NetworkTests, sendToServer_mockData)
{
// 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;
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(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler(
m_events.forCClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client));
m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &server,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockData_fileRecieveComplete));
client.connect();
m_events.initQuitTimeout(5);
m_events.loop();
m_events.cleanupQuitTimeout();
}
TEST_F(NetworkTests, sendToServer_mockFile)
{
// 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;
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(getScreenShape));
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
CClient client(&m_events, "stub", serverAddress, clientSocketFactory, NULL, &clientScreen, cryptoOptions);
m_events.adoptHandler(
m_events.forCClientListener().connected(), &listener,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client));
m_events.adoptHandler(
m_events.forIScreen().fileRecieveComplete(), &server,
new TMethodEventJob<NetworkTests>(
this, &NetworkTests::sendToServer_mockFile_fileRecieveComplete));
client.connect();
m_events.initQuitTimeout(5);
m_events.loop(); m_events.loop();
m_events.cleanupQuitTimeout(); m_events.cleanupQuitTimeout();
} }
void void
NetworkTests::sendFileToClient_handleClientConnected(const CEvent&, void* vlistener) NetworkTests::sendToClient_mockData_handleClientConnected(const CEvent&, void* vlistener)
{ {
CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener); CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
CServer* server = listener->getServer(); CServer* server = listener->getServer();
CClientProxy* client = listener->getNextClient(); CClientProxy* client = listener->getNextClient();
if (client == NULL) { if (client == NULL) {
throw std::exception("client is null"); throw runtime_error("client is null");
} }
CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client); CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client);
server->adoptClient(bcp); server->adoptClient(bcp);
server->setActive(bcp); server->setActive(bcp);
sendData(server); sendMockData(server);
} }
void void
NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*) NetworkTests::sendToClient_mockData_fileRecieveComplete(const CEvent& event, void*)
{ {
CClient* client = reinterpret_cast<CClient*>(event.getTarget()); CClient* client = reinterpret_cast<CClient*>(event.getTarget());
EXPECT_TRUE(client->isReceivedFileSizeValid()); EXPECT_TRUE(client->isReceivedFileSizeValid());
@ -147,32 +335,166 @@ NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*)
} }
void void
NetworkTests::sendData(CServer* server) NetworkTests::sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener)
{ {
UInt8* largeDataSize = new UInt8[5]; CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
largeDataSize[0] = '0'; CServer* server = listener->getServer();
largeDataSize[1] = '5';
largeDataSize[2] = '1';
largeDataSize[3] = '1';
largeDataSize[4] = '\0';
// transfer data from server -> client CClientProxy* client = listener->getNextClient();
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, largeDataSize)); if (client == NULL) {
throw runtime_error("client is null");
}
UInt8* largeData = new UInt8[klargeDataSize + 1]; CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client);
largeData[0] = '1'; server->adoptClient(bcp);
memcpy(&largeData[1], g_largeData, klargeDataSize); server->setActive(bcp);
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, (UInt8*)largeData));
UInt8* transferFinished = new UInt8[2]; server->sendFileToClient(kMockFilename);
transferFinished[0] = '2';
transferFinished[1] = '\0';
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, transferFinished));
} }
void void
sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) NetworkTests::sendToClient_mockFile_fileRecieveComplete(const CEvent& event, void*)
{
CClient* client = reinterpret_cast<CClient*>(event.getTarget());
EXPECT_TRUE(client->isReceivedFileSizeValid());
m_events.raiseQuitEvent();
}
void
NetworkTests::sendToServer_mockData_handleClientConnected(const CEvent&, void* vclient)
{
CClient* client = reinterpret_cast<CClient*>(vclient);
sendMockData(client);
}
void
NetworkTests::sendToServer_mockData_fileRecieveComplete(const CEvent& event, void*)
{
CServer* server = reinterpret_cast<CServer*>(event.getTarget());
EXPECT_TRUE(server->isReceivedFileSizeValid());
m_events.raiseQuitEvent();
}
void
NetworkTests::sendToServer_mockFile_handleClientConnected(const CEvent&, void* vclient)
{
CClient* client = reinterpret_cast<CClient*>(vclient);
client->sendFileToServer(kMockFilename);
}
void
NetworkTests::sendToServer_mockFile_fileRecieveComplete(const CEvent& event, void*)
{
CServer* server = reinterpret_cast<CServer*>(event.getTarget());
EXPECT_TRUE(server->isReceivedFileSizeValid());
m_events.raiseQuitEvent();
}
void
NetworkTests::sendMockData(void* eventTarget)
{
// send first message (file size)
CString size = intToString(kMockDataSize);
UInt32 sizeLength = size.size();
CFileChunker::CFileChunk* sizeMessage = new CFileChunker::CFileChunk(sizeLength + 2);
char* chunkData = sizeMessage->m_chunk;
chunkData[0] = kFileStart;
memcpy(&chunkData[1], size.c_str(), sizeLength);
chunkData[sizeLength + 1] = '\0';
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, sizeMessage));
// send chunk messages with incrementing chunk size
size_t lastSize = 0;
size_t sentLength = 0;
while (true) {
size_t chunkSize = lastSize + kMockDataChunkIncrement;
// make sure we don't read too much from the mock data.
if (sentLength + chunkSize > kMockDataSize) {
chunkSize = kMockDataSize - sentLength;
}
// first byte is the chunk mark, last is \0
CFileChunker::CFileChunk* fileChunk = new CFileChunker::CFileChunk(chunkSize + 2);
char* chunkData = fileChunk->m_chunk;
chunkData[0] = kFileChunk;
memcpy(&chunkData[1], &m_mockData[sentLength], chunkSize);
chunkData[chunkSize + 1] = '\0';
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, fileChunk));
sentLength += chunkSize;
lastSize = chunkSize;
if (sentLength == kMockDataSize) {
break;
}
}
// send last message
CFileChunker::CFileChunk* transferFinished = new CFileChunker::CFileChunk(2);
chunkData = transferFinished->m_chunk;
chunkData[0] = kFileEnd;
chunkData[1] = '\0';
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), eventTarget, transferFinished));
}
UInt8*
newMockData(size_t size)
{
UInt8* buffer = new UInt8[size];
UInt8* data = buffer;
const UInt8 head[] = "mock head... ";
size_t headSize = sizeof(head) - 1;
const UInt8 tail[] = "... mock tail";
size_t tailSize = sizeof(tail) - 1;
const UInt8 synergyRocks[] = "synergy\0 rocks! ";
size_t synergyRocksSize = sizeof(synergyRocks) - 1;
memcpy(data, head, headSize);
data += headSize;
SInt32 times = (size - headSize - tailSize) / synergyRocksSize;
for (SInt32 i = 0; i < times; ++i) {
memcpy(data, synergyRocks, synergyRocksSize);
data += synergyRocksSize;
}
SInt32 remainder = (size - headSize - tailSize) % synergyRocksSize;
if (remainder != 0) {
memset(data, '.', remainder);
data += remainder;
}
memcpy(data, tail, tailSize);
return buffer;
}
void
createFile(fstream& file, const char* filename, size_t size)
{
UInt8* buffer = newMockData(size);
file.open(filename, ios::out | ios::binary);
if (!file.is_open()) {
throw runtime_error("file not open");
}
file.write(reinterpret_cast<char*>(buffer), size);
file.close();
delete[] buffer;
}
void
getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h)
{ {
x = 0; x = 0;
y = 0; y = 0;
@ -181,8 +503,16 @@ sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h)
} }
void void
sendFileToClient_getCursorPos(SInt32& x, SInt32& y) getCursorPos(SInt32& x, SInt32& y)
{ {
x = 0; x = 0;
y = 0; y = 0;
} }
CString
intToString(size_t i)
{
stringstream ss;
ss << i;
return ss.str();
}

View File

@ -20,8 +20,8 @@
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include "COSXKeyState.h" #include "COSXKeyState.h"
#include "CMockKeyMap.h" #include "synergy/CMockKeyMap.h"
#include "CMockEventQueue.h" #include "synergy/CMockEventQueue.h"
#include "CLog.h" #include "CLog.h"

View File

@ -22,8 +22,8 @@
#define TEST_ENV #define TEST_ENV
#include "Global.h" #include "Global.h"
#include "CMockKeyMap.h" #include "synergy/CMockKeyMap.h"
#include "CMockEventQueue.h" #include "synergy/CMockEventQueue.h"
#include "CXWindowsKeyState.h" #include "CXWindowsKeyState.h"
#include "CLog.h" #include "CLog.h"
#include <errno.h> #include <errno.h>

View File

@ -18,7 +18,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include "CXWindowsScreen.h" #include "CXWindowsScreen.h"
#include "CMockEventQueue.h" #include "synergy/CMockEventQueue.h"
using ::testing::_; using ::testing::_;

View File

@ -48,8 +48,8 @@ TEST(CServerProxyTests, mouseMove)
g_mouseMove_bufferIndex = 0; g_mouseMove_bufferIndex = 0;
NiceMock<CMockEventQueue> eventQueue; NiceMock<CMockEventQueue> eventQueue;
NiceMock<CMockClient> client;
NiceMock<CMockStream> stream; NiceMock<CMockStream> stream;
NiceMock<CMockClient> client;
IStreamEvents streamEvents; IStreamEvents streamEvents;
streamEvents.setEvents(&eventQueue); streamEvents.setEvents(&eventQueue);