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:
parent
c368013f13
commit
394ece004a
|
@ -178,7 +178,7 @@ CLog::print(const char* file, int line, const char* fmt, ...)
|
|||
// do not prefix time and file for kPRINT (CLOG_PRINT)
|
||||
if (priority != kPRINT) {
|
||||
|
||||
char message[2048];
|
||||
char message[kLogMessageLength];
|
||||
|
||||
#ifndef NDEBUG
|
||||
struct tm *tm;
|
||||
|
|
|
@ -137,6 +137,8 @@ private:
|
|||
int m_maxPriority;
|
||||
};
|
||||
|
||||
const UInt16 kLogMessageLength = 2048;
|
||||
|
||||
/*!
|
||||
\def LOG(arg)
|
||||
Write to the log. Because macros cannot accept variable arguments, this
|
||||
|
|
|
@ -33,14 +33,20 @@
|
|||
#include "CArch.h"
|
||||
#include "IPlatformScreen.h"
|
||||
#include "CCryptoStream.h"
|
||||
#include "CThread.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CFileChunker.h"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
||||
//
|
||||
// CClient
|
||||
//
|
||||
|
||||
const size_t CClient::m_chunkSize = 1024 * 512; // 512kb
|
||||
|
||||
CClient::CClient(IEventQueue* events,
|
||||
const CString& name, const CNetworkAddress& address,
|
||||
ISocketFactory* socketFactory,
|
||||
|
@ -438,6 +444,17 @@ CClient::sendConnectionFailedEvent(const char* msg)
|
|||
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
|
||||
CClient::setupConnecting()
|
||||
{
|
||||
|
@ -737,6 +754,7 @@ CClient::handleGameDeviceFeedback(const CEvent& event, void*)
|
|||
void
|
||||
CClient::handleFileChunkSending(const CEvent& event, void*)
|
||||
{
|
||||
sendFileChunk(event.getData());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -763,3 +781,24 @@ CClient::isReceivedFileSizeValid()
|
|||
{
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,8 +101,8 @@ public:
|
|||
//! Received a chunk of file data
|
||||
void fileChunkReceived(CString data);
|
||||
|
||||
//! Return true if recieved file size is valid
|
||||
bool isReceivedFileSizeValid();
|
||||
//! Create a new thread and use it to send file to Server
|
||||
void sendFileToServer(const char* filename);
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
|
@ -128,6 +128,9 @@ public:
|
|||
*/
|
||||
CNetworkAddress getServerAddress() const;
|
||||
|
||||
//! Return true if recieved file size is valid
|
||||
bool isReceivedFileSizeValid();
|
||||
|
||||
//@}
|
||||
|
||||
// IScreen overrides
|
||||
|
@ -167,6 +170,8 @@ private:
|
|||
void sendClipboard(ClipboardID);
|
||||
void sendEvent(CEvent::Type, void*);
|
||||
void sendConnectionFailedEvent(const char* msg);
|
||||
void sendFileChunk(const void* data);
|
||||
void sendFileThread(void*);
|
||||
void setupConnecting();
|
||||
void setupConnection();
|
||||
void setupScreen();
|
||||
|
@ -214,6 +219,7 @@ private:
|
|||
CCryptoOptions m_crypto;
|
||||
std::size_t m_expectedFileSize;
|
||||
CString m_receivedFileData;
|
||||
static const size_t m_chunkSize;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -935,7 +935,8 @@ CServerProxy::infoAcknowledgment()
|
|||
m_ignoreMouse = false;
|
||||
}
|
||||
|
||||
void CServerProxy::fileChunkReceived()
|
||||
void
|
||||
CServerProxy::fileChunkReceived()
|
||||
{
|
||||
// parse
|
||||
UInt8 mark;
|
||||
|
@ -943,20 +944,42 @@ void CServerProxy::fileChunkReceived()
|
|||
CProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content);
|
||||
|
||||
switch (mark) {
|
||||
case '0':
|
||||
LOG((CLOG_DEBUG2 "recv file data: file size = %s", content));
|
||||
case kFileStart:
|
||||
LOG((CLOG_DEBUG2 "recv file data from server: size=%s", content.c_str()));
|
||||
m_client->clearReceivedFileData();
|
||||
m_client->setExpectedFileSize(content);
|
||||
break;
|
||||
|
||||
case '1':
|
||||
LOG((CLOG_DEBUG2 "recv file data: chunck size = %i", content.size()));
|
||||
case kFileChunk:
|
||||
LOG((CLOG_DEBUG2 "recv file data from server: size=%i", content.size()));
|
||||
m_client->fileChunkReceived(content);
|
||||
break;
|
||||
|
||||
case '2':
|
||||
case kFileEnd:
|
||||
LOG((CLOG_DEBUG2 "file data transfer finished"));
|
||||
m_events->addEvent(CEvent(m_events->forIScreen().fileRecieveComplete(), m_client));
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,14 @@ public:
|
|||
|
||||
//@}
|
||||
|
||||
//! @file transfer
|
||||
//@{
|
||||
|
||||
//! sending file chunk to server
|
||||
void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
|
||||
|
||||
//@}
|
||||
|
||||
#ifdef TEST_ENV
|
||||
void handleDataForTest() { handleData(CEvent(), NULL); }
|
||||
#endif
|
||||
|
|
|
@ -83,7 +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 void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0;
|
||||
virtual CString getName() const;
|
||||
|
||||
private:
|
||||
|
|
|
@ -89,7 +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;
|
||||
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0;
|
||||
|
||||
private:
|
||||
synergy::IStream* m_stream;
|
||||
|
|
|
@ -394,7 +394,7 @@ CClientProxy1_0::cryptoIv(const UInt8* iv)
|
|||
}
|
||||
|
||||
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
|
||||
LOG((CLOG_DEBUG "fileChunkSending not supported"));
|
||||
|
|
|
@ -64,7 +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);
|
||||
virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize);
|
||||
|
||||
protected:
|
||||
virtual bool parseHandshakeMessage(const UInt8* code);
|
||||
|
|
|
@ -42,7 +42,6 @@ protected:
|
|||
private:
|
||||
void handleKeepAlive(const CEvent&, void*);
|
||||
|
||||
|
||||
private:
|
||||
double m_keepAliveRate;
|
||||
CEventQueueTimer* m_keepAliveTimer;
|
||||
|
|
|
@ -29,6 +29,14 @@ public:
|
|||
CClientProxy1_4(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events);
|
||||
~CClientProxy1_4();
|
||||
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! get server pointer
|
||||
CServer* getServer() { return m_server; }
|
||||
|
||||
//@}
|
||||
|
||||
// IClient overrides
|
||||
virtual void gameDeviceButtons(GameDeviceID id, GameDeviceButton buttons);
|
||||
virtual void gameDeviceSticks(GameDeviceID id, SInt16 x1, SInt16 y1, SInt16 x2, SInt16 y2);
|
||||
|
|
|
@ -19,13 +19,15 @@
|
|||
#include "CProtocolUtil.h"
|
||||
#include "CLog.h"
|
||||
#include "IStream.h"
|
||||
#include "CServer.h"
|
||||
|
||||
//
|
||||
// CClientProxy1_5
|
||||
//
|
||||
|
||||
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
|
||||
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) {
|
||||
case '0':
|
||||
LOG((CLOG_DEBUG2 "file sending start: file size = %s", data));
|
||||
case kFileStart:
|
||||
LOG((CLOG_DEBUG2 "file sending start: size=%s", data));
|
||||
break;
|
||||
|
||||
case '1':
|
||||
LOG((CLOG_DEBUG2 "file chunk sending: %s", data));
|
||||
case kFileChunk:
|
||||
LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size()));
|
||||
break;
|
||||
|
||||
case '2':
|
||||
case kFileEnd:
|
||||
LOG((CLOG_DEBUG2 "file sending finished"));
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,5 +28,10 @@ public:
|
|||
CClientProxy1_5(const CString& name, synergy::IStream* adoptedStream, CServer* server, IEventQueue* events);
|
||||
~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;
|
||||
};
|
||||
|
|
|
@ -274,7 +274,7 @@ CPrimaryClient::screensaver(bool)
|
|||
}
|
||||
|
||||
void
|
||||
CPrimaryClient::fileChunkSending(UInt8 mark, const UInt8* data)
|
||||
CPrimaryClient::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
|
|
@ -148,7 +148,7 @@ public:
|
|||
virtual void screensaver(bool activate);
|
||||
virtual void resetOptions();
|
||||
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:
|
||||
CScreen* m_screen;
|
||||
|
|
|
@ -33,14 +33,22 @@
|
|||
#include "TMethodEventJob.h"
|
||||
#include "CArch.h"
|
||||
#include "CKeyState.h"
|
||||
#include "CScreen.h"
|
||||
#include "CThread.h"
|
||||
#include "TMethodJob.h"
|
||||
#include "CFileChunker.h"
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include "CScreen.h"
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
//
|
||||
// CServer
|
||||
//
|
||||
|
||||
const size_t CServer::m_chunkSize = 1024 * 512; // 512kb
|
||||
|
||||
CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen, IEventQueue* events) :
|
||||
m_events(events),
|
||||
m_mock(false),
|
||||
|
@ -177,6 +185,10 @@ CServer::CServer(CConfig& config, CPrimaryClient* primaryClient, CScreen* screen
|
|||
this,
|
||||
new TMethodEventJob<CServer>(this,
|
||||
&CServer::handleFileChunkSendingEvent));
|
||||
m_events->adoptHandler(m_events->forIScreen().fileRecieveComplete(),
|
||||
this,
|
||||
new TMethodEventJob<CServer>(this,
|
||||
&CServer::handleFileRecieveCompleteEvent));
|
||||
|
||||
// add connection
|
||||
addClient(m_primaryClient);
|
||||
|
@ -1516,8 +1528,13 @@ CServer::handleFakeInputEndEvent(const CEvent&, void*)
|
|||
void
|
||||
CServer::handleFileChunkSendingEvent(const CEvent& event, void*)
|
||||
{
|
||||
UInt8* data = reinterpret_cast<UInt8*>(event.getData());
|
||||
onFileChunkSending(data);
|
||||
onFileChunkSending(event.getData());
|
||||
}
|
||||
|
||||
void
|
||||
CServer::handleFileRecieveCompleteEvent(const CEvent& event, void*)
|
||||
{
|
||||
onFileRecieveComplete();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1981,13 +1998,32 @@ CServer::onGameDeviceTimingReq()
|
|||
}
|
||||
|
||||
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"));
|
||||
assert(m_active != NULL);
|
||||
|
||||
// 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
|
||||
|
@ -2260,3 +2296,49 @@ CServer::CKeyboardBroadcastInfo::alloc(State state, const CString& screens)
|
|||
strcpy(info->m_screens, screens.c_str());
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,6 +144,21 @@ public:
|
|||
//! Notify of game device feedback
|
||||
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
|
||||
//@{
|
||||
|
@ -160,6 +175,9 @@ public:
|
|||
*/
|
||||
void getClients(std::vector<CString>& list) const;
|
||||
|
||||
//! Return true if recieved file size is valid
|
||||
bool isReceivedFileSizeValid();
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
|
@ -299,6 +317,7 @@ private:
|
|||
void handleFakeInputBeginEvent(const CEvent&, void*);
|
||||
void handleFakeInputEndEvent(const CEvent&, void*);
|
||||
void handleFileChunkSendingEvent(const CEvent&, void*);
|
||||
void handleFileRecieveCompleteEvent(const CEvent&, void*);
|
||||
|
||||
// event processing
|
||||
void onClipboardChanged(CBaseClientProxy* sender,
|
||||
|
@ -318,7 +337,8 @@ 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);
|
||||
void onFileChunkSending(const void* data);
|
||||
void onFileRecieveComplete();
|
||||
|
||||
// add client to list and attach event handlers for client
|
||||
bool addClient(CBaseClientProxy*);
|
||||
|
@ -343,6 +363,9 @@ private:
|
|||
// force the cursor off of \p client
|
||||
void forceLeaveClient(CBaseClientProxy* client);
|
||||
|
||||
// thread funciton for sending file
|
||||
void sendFileThread(void*);
|
||||
|
||||
public:
|
||||
bool m_mock;
|
||||
|
||||
|
@ -438,6 +461,13 @@ private:
|
|||
CScreen* m_screen;
|
||||
|
||||
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
|
||||
|
|
|
@ -171,6 +171,14 @@ CApp::parseArg(const int& argc, const char* const* argv, int& 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 {
|
||||
// option not supported here
|
||||
return false;
|
||||
|
|
|
@ -101,6 +101,9 @@ public:
|
|||
void setSocketMultiplexer(CSocketMultiplexer* sm) { m_socketMultiplexer = sm; }
|
||||
CSocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; }
|
||||
|
||||
CString& getFileTransferSrc() { return m_fileTransferSrc; }
|
||||
CString& getFileTransferDes() { return m_fileTransferDes; }
|
||||
|
||||
private:
|
||||
void handleIpcMessage(const CEvent&, void*);
|
||||
|
||||
|
@ -122,6 +125,8 @@ private:
|
|||
CIpcClient* m_ipcClient;
|
||||
IEventQueue* m_events;
|
||||
CSocketMultiplexer* m_socketMultiplexer;
|
||||
CString m_fileTransferSrc;
|
||||
CString m_fileTransferDes;
|
||||
};
|
||||
|
||||
#define BYE "\nTry `%s --help' for more information."
|
||||
|
|
|
@ -349,6 +349,14 @@ CClientApp::handleClientConnected(const CEvent&, void*)
|
|||
LOG((CLOG_NOTE "connected to server"));
|
||||
resetRestartTimeout();
|
||||
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
|
||||
|
||||
s_client->connect();
|
||||
|
||||
updateStatus();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -49,6 +49,7 @@ set(inc
|
|||
CArgsBase.h
|
||||
IAppUtil.h
|
||||
CEventGameDevice.h
|
||||
CFileChunker.h
|
||||
)
|
||||
|
||||
set(src
|
||||
|
@ -77,6 +78,7 @@ set(src
|
|||
CArgsBase.cpp
|
||||
CEventGameDevice.cpp
|
||||
CGameDevice.cpp
|
||||
CFileChunker.cpp
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
|
|
|
@ -228,7 +228,12 @@ CProtocolUtil::vreadf(synergy::IStream* stream, const char* fmt, va_list args)
|
|||
}
|
||||
throw;
|
||||
}
|
||||
LOG((CLOG_DEBUG2 "readf: read %d byte string: %.*s", len, len, sBuffer));
|
||||
|
||||
// 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));
|
||||
}
|
||||
|
||||
// save the data
|
||||
CString* dst = va_arg(args, CString*);
|
||||
|
|
|
@ -688,7 +688,7 @@ CServer*
|
|||
CServerApp::openServer(CConfig& config, CPrimaryClient* primaryClient)
|
||||
{
|
||||
CServer* server = new CServer(config, primaryClient, s_serverScreen, m_events);
|
||||
|
||||
server->setFileTransferDes(getFileTransferDes());
|
||||
try {
|
||||
m_events->adoptHandler(
|
||||
m_events->forCServer().disconnected(), server,
|
||||
|
|
|
@ -68,6 +68,13 @@ enum EDirectionMask {
|
|||
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
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "CLog.h"
|
||||
#include "TMethodEventJob.h"
|
||||
#include "CSimpleEventQueueBuffer.h"
|
||||
#include <stdexcept>
|
||||
|
||||
void
|
||||
CTestEventQueue::raiseQuitEvent()
|
||||
|
@ -47,6 +48,5 @@ CTestEventQueue::cleanupQuitTimeout()
|
|||
void
|
||||
CTestEventQueue::handleQuitTimeout(const CEvent&, void* vclient)
|
||||
{
|
||||
LOG((CLOG_ERR "timeout"));
|
||||
raiseQuitEvent();
|
||||
throw std::runtime_error("test event queue timeout");
|
||||
}
|
||||
|
|
|
@ -16,8 +16,11 @@
|
|||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
|
||||
#define TEST_ENV
|
||||
|
||||
|
@ -33,13 +36,14 @@
|
|||
#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"
|
||||
#include "TMethodJob.h"
|
||||
#include "CThread.h"
|
||||
#include "CFileChunker.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using ::testing::_;
|
||||
using ::testing::NiceMock;
|
||||
using ::testing::Return;
|
||||
|
@ -48,27 +52,58 @@ 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";
|
||||
const size_t kMockDataSize = 1024 * 1024 * 10; // 10MB
|
||||
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 sendFileToClient_getCursorPos(SInt32& x, SInt32& y);
|
||||
void getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h);
|
||||
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
|
||||
{
|
||||
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 sendFileToClient_fileRecieveComplete(const CEvent&, void*);
|
||||
void sendMockData(void* eventTarget);
|
||||
|
||||
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:
|
||||
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
|
||||
CNetworkAddress serverAddress(TEST_HOST, TEST_PORT);
|
||||
|
@ -88,7 +123,7 @@ TEST_F(NetworkTests, sendFileToClient)
|
|||
m_events.adoptHandler(
|
||||
m_events.forCClientListener().connected(), &listener,
|
||||
new TMethodEventJob<NetworkTests>(
|
||||
this, &NetworkTests::sendFileToClient_handleClientConnected, &listener));
|
||||
this, &NetworkTests::sendToClient_mockData_handleClientConnected, &listener));
|
||||
|
||||
ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true));
|
||||
ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter));
|
||||
|
@ -102,43 +137,196 @@ TEST_F(NetworkTests, sendFileToClient)
|
|||
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));
|
||||
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::sendFileToClient_fileRecieveComplete));
|
||||
this, &NetworkTests::sendToClient_mockData_fileRecieveComplete));
|
||||
|
||||
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.cleanupQuitTimeout();
|
||||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendFileToClient_handleClientConnected(const CEvent&, void* vlistener)
|
||||
NetworkTests::sendToClient_mockData_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");
|
||||
throw runtime_error("client is null");
|
||||
}
|
||||
|
||||
CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client);
|
||||
server->adoptClient(bcp);
|
||||
server->setActive(bcp);
|
||||
|
||||
sendData(server);
|
||||
sendMockData(server);
|
||||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*)
|
||||
NetworkTests::sendToClient_mockData_fileRecieveComplete(const CEvent& event, void*)
|
||||
{
|
||||
CClient* client = reinterpret_cast<CClient*>(event.getTarget());
|
||||
EXPECT_TRUE(client->isReceivedFileSizeValid());
|
||||
|
@ -147,32 +335,166 @@ NetworkTests::sendFileToClient_fileRecieveComplete(const CEvent& event, void*)
|
|||
}
|
||||
|
||||
void
|
||||
NetworkTests::sendData(CServer* server)
|
||||
NetworkTests::sendToClient_mockFile_handleClientConnected(const CEvent&, void* vlistener)
|
||||
{
|
||||
UInt8* largeDataSize = new UInt8[5];
|
||||
largeDataSize[0] = '0';
|
||||
largeDataSize[1] = '5';
|
||||
largeDataSize[2] = '1';
|
||||
largeDataSize[3] = '1';
|
||||
largeDataSize[4] = '\0';
|
||||
CClientListener* listener = reinterpret_cast<CClientListener*>(vlistener);
|
||||
CServer* server = listener->getServer();
|
||||
|
||||
// transfer data from server -> client
|
||||
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, largeDataSize));
|
||||
CClientProxy* client = listener->getNextClient();
|
||||
if (client == NULL) {
|
||||
throw runtime_error("client is null");
|
||||
}
|
||||
|
||||
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));
|
||||
CBaseClientProxy* bcp = reinterpret_cast<CBaseClientProxy*>(client);
|
||||
server->adoptClient(bcp);
|
||||
server->setActive(bcp);
|
||||
|
||||
UInt8* transferFinished = new UInt8[2];
|
||||
transferFinished[0] = '2';
|
||||
transferFinished[1] = '\0';
|
||||
|
||||
m_events.addEvent(CEvent(m_events.forIScreen().fileChunkSending(), server, transferFinished));
|
||||
server->sendFileToClient(kMockFilename);
|
||||
}
|
||||
|
||||
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;
|
||||
y = 0;
|
||||
|
@ -181,8 +503,16 @@ sendFileToClient_getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h)
|
|||
}
|
||||
|
||||
void
|
||||
sendFileToClient_getCursorPos(SInt32& x, SInt32& y)
|
||||
getCursorPos(SInt32& x, SInt32& y)
|
||||
{
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
CString
|
||||
intToString(size_t i)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << i;
|
||||
return ss.str();
|
||||
}
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
#include <gmock/gmock.h>
|
||||
|
||||
#include "COSXKeyState.h"
|
||||
#include "CMockKeyMap.h"
|
||||
#include "CMockEventQueue.h"
|
||||
#include "synergy/CMockKeyMap.h"
|
||||
#include "synergy/CMockEventQueue.h"
|
||||
|
||||
#include "CLog.h"
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
#define TEST_ENV
|
||||
#include "Global.h"
|
||||
|
||||
#include "CMockKeyMap.h"
|
||||
#include "CMockEventQueue.h"
|
||||
#include "synergy/CMockKeyMap.h"
|
||||
#include "synergy/CMockEventQueue.h"
|
||||
#include "CXWindowsKeyState.h"
|
||||
#include "CLog.h"
|
||||
#include <errno.h>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include <gtest/gtest.h>
|
||||
#include "CXWindowsScreen.h"
|
||||
#include "CMockEventQueue.h"
|
||||
#include "synergy/CMockEventQueue.h"
|
||||
|
||||
using ::testing::_;
|
||||
|
||||
|
|
|
@ -48,8 +48,8 @@ TEST(CServerProxyTests, mouseMove)
|
|||
g_mouseMove_bufferIndex = 0;
|
||||
|
||||
NiceMock<CMockEventQueue> eventQueue;
|
||||
NiceMock<CMockClient> client;
|
||||
NiceMock<CMockStream> stream;
|
||||
NiceMock<CMockClient> client;
|
||||
IStreamEvents streamEvents;
|
||||
streamEvents.setEvents(&eventQueue);
|
||||
|
||||
|
|
Loading…
Reference in New Issue