From 44089d55e83b6fcaea196b1eb83635f2de86865d Mon Sep 17 00:00:00 2001 From: "Jerry (Xinyu Hou)" Date: Fri, 15 May 2015 14:26:57 -0700 Subject: [PATCH] Send clipboard data in small chunks without using thread #4601 --- src/lib/client/ServerProxy.cpp | 43 +++++---- src/lib/server/ClientProxy1_5.cpp | 110 ++++++++++++++++++++--- src/lib/server/ClientProxy1_5.h | 4 +- src/lib/synergy/FileChunker.cpp | 6 +- src/lib/synergy/protocol_types.cpp | 2 +- src/lib/synergy/protocol_types.h | 11 ++- src/test/integtests/net/NetworkTests.cpp | 6 +- 7 files changed, 137 insertions(+), 45 deletions(-) diff --git a/src/lib/client/ServerProxy.cpp b/src/lib/client/ServerProxy.cpp index 914dd4ee..c50e44d9 100644 --- a/src/lib/client/ServerProxy.cpp +++ b/src/lib/client/ServerProxy.cpp @@ -545,21 +545,32 @@ void ServerProxy::setClipboard() { // parse + static String dataCached; ClipboardID id; UInt32 seqNum; + size_t mark = 0; String data; - ProtocolUtil::readf(m_stream, kMsgDClipboard + 4, &id, &seqNum, &data); - LOG((CLOG_DEBUG "recv clipboard %d size=%d", id, data.size())); + ProtocolUtil::readf(m_stream, kMsgDClipboard + 4, &id, &seqNum, &mark, &data); - // validate - if (id >= kClipboardEnd) { - return; + if (mark == kDataStart) { + //TODO: validate size + LOG((CLOG_DEBUG "start receiving clipboard data")); + dataCached.clear(); + } + else if (mark == kDataChunk) { + dataCached.append(data); + } + else if (mark == kDataEnd) { + LOG((CLOG_DEBUG "received clipboard %d size=%d", id, dataCached.size())); + // validate + if (id >= kClipboardEnd) { + return; + } + // forward + Clipboard clipboard; + clipboard.unmarshall(dataCached, 0); + m_client->setClipboard(id, &clipboard); } - - // forward - Clipboard clipboard; - clipboard.unmarshall(data, 0); - m_client->setClipboard(id, &clipboard); } void @@ -857,7 +868,7 @@ ServerProxy::fileChunkReceived() ProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content); switch (mark) { - case kFileStart: + case kDataStart: m_client->clearReceivedFileData(); m_client->setExpectedFileSize(content); if (CLOG->getFilter() >= kDEBUG2) { @@ -866,7 +877,7 @@ ServerProxy::fileChunkReceived() } break; - case kFileChunk: + case kDataChunk: m_client->fileChunkReceived(content); if (CLOG->getFilter() >= kDEBUG2) { LOG((CLOG_DEBUG2 "recv file data from server: size=%i", content.size())); @@ -884,7 +895,7 @@ ServerProxy::fileChunkReceived() } break; - case kFileEnd: + case kDataEnd: m_events->addEvent(Event(m_events->forIScreen().fileRecieveCompleted(), m_client)); if (CLOG->getFilter() >= kDEBUG2) { LOG((CLOG_DEBUG2 "file data transfer finished")); @@ -915,15 +926,15 @@ ServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize) String chunk(data, dataSize); switch (mark) { - case kFileStart: + case kDataStart: LOG((CLOG_DEBUG2 "file sending start: size=%s", data)); break; - case kFileChunk: + case kDataChunk: LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size())); break; - case kFileEnd: + case kDataEnd: LOG((CLOG_DEBUG2 "file sending finished")); break; } diff --git a/src/lib/server/ClientProxy1_5.cpp b/src/lib/server/ClientProxy1_5.cpp index 34c30e83..a0d082eb 100644 --- a/src/lib/server/ClientProxy1_5.cpp +++ b/src/lib/server/ClientProxy1_5.cpp @@ -18,12 +18,15 @@ #include "server/ClientProxy1_5.h" #include "server/Server.h" +#include "synergy/FileChunker.h" #include "synergy/ProtocolUtil.h" #include "mt/Thread.h" #include "io/IStream.h" #include "base/TMethodJob.h" #include "base/Log.h" +#include + // // ClientProxy1_5 // @@ -57,15 +60,15 @@ ClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize) String chunk(data, dataSize); switch (mark) { - case kFileStart: + case kDataStart: LOG((CLOG_DEBUG2 "file sending start: size=%s", data)); break; - case kFileChunk: + case kDataChunk: LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size())); break; - case kFileEnd: + case kDataEnd: LOG((CLOG_DEBUG2 "file sending finished")); break; } @@ -82,12 +85,50 @@ ClientProxy1_5::setClipboard(ClipboardID id, const IClipboard* clipboard) m_clipboard[id].m_dirty = false; Clipboard::copy(&m_clipboard[id].m_clipboard, clipboard); - m_clipboardData = m_clipboard[id].m_clipboard.marshall(); + String data = m_clipboard[id].m_clipboard.marshall(); - m_sendFileThread = new Thread( - new TMethodJob( - this, &ClientProxy1_5::sendClipboardThread, - reinterpret_cast(id))); + size_t size = data.size(); + LOG((CLOG_DEBUG "sending clipboard %d to \"%s\" size=%d", id, getName().c_str(), size)); + + //TODO: refactor FileChunker and use thread + // send first message (file size) + std::stringstream ss; + ss << size; + String dataSize = ss.str(); + ProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, kDataStart, &dataSize); + + // send chunk messages with a fixed chunk size + size_t sentLength = 0; + size_t chunkSize = 2048; + Stopwatch stopwatch; + stopwatch.start(); + while (true) { + if (stopwatch.getTime() > 0.1f) { + // make sure we don't read too much from the mock data. + if (sentLength + chunkSize > size) { + chunkSize = size - sentLength; + } + + String chunk(data.substr(sentLength, chunkSize).c_str(), chunkSize); + ProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, kDataChunk, &chunk); + + sentLength += chunkSize; + + if (sentLength == size) { + break; + } + + stopwatch.reset(); + } + } + + // send last message + ProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, kDataEnd, "\0"); + +// m_sendFileThread = new Thread( +// new TMethodJob( +// this, &ClientProxy1_5::sendClipboardThread, +// reinterpret_cast(id))); } } @@ -117,7 +158,7 @@ ClientProxy1_5::fileChunkReceived() Server* server = getServer(); switch (mark) { - case kFileStart: + case kDataStart: server->clearReceivedFileData(); server->setExpectedFileSize(content); if (CLOG->getFilter() >= kDEBUG2) { @@ -126,7 +167,7 @@ ClientProxy1_5::fileChunkReceived() } break; - case kFileChunk: + case kDataChunk: server->fileChunkReceived(content); if (CLOG->getFilter() >= kDEBUG2) { LOG((CLOG_DEBUG2 "recv file data from client: chunck size=%i", content.size())); @@ -144,7 +185,7 @@ ClientProxy1_5::fileChunkReceived() } break; - case kFileEnd: + case kDataEnd: m_events->addEvent(Event(m_events->forIScreen().fileRecieveCompleted(), server)); if (CLOG->getFilter() >= kDEBUG2) { LOG((CLOG_DEBUG2 "file data transfer finished")); @@ -172,7 +213,48 @@ ClientProxy1_5::dragInfoReceived() void ClientProxy1_5::sendClipboardThread(void* data) { - size_t id = reinterpret_cast(data); - LOG((CLOG_DEBUG "sending clipboard %d to \"%s\" size=%d", id, getName().c_str(), m_clipboardData.size())); - ProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &m_clipboardData); + //size_t id = reinterpret_cast(data); + //String clipboardData = m_clipboardData.at(id); + //int size = clipboardData.size(); + //LOG((CLOG_DEBUG "sending clipboard %d to \"%s\" size=%d", id, getName().c_str(), size)); + + ////TODO: refactor FileChunker + //// send first message (file size) + //std::stringstream ss; + //ss << size; + //String dataSize = ss.str(); + //ProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, kDataStart, &dataSize); + + //// send chunk messages with a fixed chunk size + //size_t sentLength = 0; + //size_t chunkSize = 2048; + //Stopwatch stopwatch; + //stopwatch.start(); + //while (true) { + // if (stopwatch.getTime() > 0.1f) { + // // make sure we don't read too much from the mock data. + // if (sentLength + chunkSize > size) { + // chunkSize = size - sentLength; + // } + + // char* chunk = new char[chunkSize]; + // memcpy(chunk, clipboardData.substr(sentLength, chunkSize).c_str(), chunkSize); + // //String chunk(clipboardData.substr(sentLength, chunkSize).c_str(), chunkSize); + // //int sizetest = chunk.size(); + // //sizetest++; + // //sizetest--; + // ProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, kDataChunk, chunk); + + // sentLength += chunkSize; + + // if (sentLength == size) { + // break; + // } + + // stopwatch.reset(); + // } + //} + + //// send last message + //ProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, kDataEnd, "\0"); } diff --git a/src/lib/server/ClientProxy1_5.h b/src/lib/server/ClientProxy1_5.h index 03ddbac6..8301d3be 100644 --- a/src/lib/server/ClientProxy1_5.h +++ b/src/lib/server/ClientProxy1_5.h @@ -19,6 +19,7 @@ #include "server/ClientProxy1_4.h" #include "base/Stopwatch.h" +#include "common/stdvector.h" class Server; class IEventQueue; @@ -48,6 +49,5 @@ private: double m_elapsedTime; size_t m_receivedDataSize; static const UInt16 m_intervalThreshold; - Thread* m_sendFileThread; - String m_clipboardData; + //Thread* m_sendFileThread; }; diff --git a/src/lib/synergy/FileChunker.cpp b/src/lib/synergy/FileChunker.cpp index 7936ecc6..d0289eca 100644 --- a/src/lib/synergy/FileChunker.cpp +++ b/src/lib/synergy/FileChunker.cpp @@ -54,7 +54,7 @@ FileChunker::sendFileChunks(char* filename, IEventQueue* events, void* eventTarg FileChunk* sizeMessage = new FileChunk(sizeLength + 2); char* chunkData = sizeMessage->m_chunk; - chunkData[0] = kFileStart; + chunkData[0] = kDataStart; memcpy(&chunkData[1], fileSize.c_str(), sizeLength); chunkData[sizeLength + 1] = '\0'; events->addEvent(Event(events->forIScreen().fileChunkSending(), eventTarget, sizeMessage)); @@ -76,7 +76,7 @@ FileChunker::sendFileChunks(char* filename, IEventQueue* events, void* eventTarg FileChunk* fileChunk = new FileChunk(chunkSize + 2); char* chunkData = fileChunk->m_chunk; - chunkData[0] = kFileChunk; + chunkData[0] = kDataChunk; file.read(&chunkData[1], chunkSize); chunkData[chunkSize + 1] = '\0'; events->addEvent(Event(events->forIScreen().fileChunkSending(), eventTarget, fileChunk)); @@ -96,7 +96,7 @@ FileChunker::sendFileChunks(char* filename, IEventQueue* events, void* eventTarg FileChunk* transferFinished = new FileChunk(2); chunkData = transferFinished->m_chunk; - chunkData[0] = kFileEnd; + chunkData[0] = kDataEnd; chunkData[1] = '\0'; events->addEvent(Event(events->forIScreen().fileChunkSending(), eventTarget, transferFinished)); diff --git a/src/lib/synergy/protocol_types.cpp b/src/lib/synergy/protocol_types.cpp index 9f2eef9d..1e274b06 100644 --- a/src/lib/synergy/protocol_types.cpp +++ b/src/lib/synergy/protocol_types.cpp @@ -41,7 +41,7 @@ const char* kMsgDMouseMove = "DMMV%2i%2i"; const char* kMsgDMouseRelMove = "DMRM%2i%2i"; const char* kMsgDMouseWheel = "DMWM%2i%2i"; const char* kMsgDMouseWheel1_0 = "DMWM%2i"; -const char* kMsgDClipboard = "DCLP%1i%4i%s"; +const char* kMsgDClipboard = "DCLP%1i%4i%1i%s"; const char* kMsgDInfo = "DINF%2i%2i%2i%2i%2i%2i%2i"; const char* kMsgDSetOptions = "DSOP%4I"; const char* kMsgDFileTransfer = "DFTR%1i%s"; diff --git a/src/lib/synergy/protocol_types.h b/src/lib/synergy/protocol_types.h index 4391605c..956f4f49 100644 --- a/src/lib/synergy/protocol_types.h +++ b/src/lib/synergy/protocol_types.h @@ -70,13 +70,12 @@ enum EDirectionMask { }; // file transfer constants -enum EFileTransfer { - kFileStart = 1, - kFileChunk = 2, - kFileEnd = 3 +enum EDataTransfer { + kDataStart = 1, + kDataChunk = 2, + kDataEnd = 3 }; - // // message codes (trailing NUL is not part of code). in comments, $n // refers to the n'th argument (counting from one). message codes are @@ -225,7 +224,7 @@ extern const char* kMsgDMouseWheel; extern const char* kMsgDMouseWheel1_0; // clipboard data: primary <-> secondary -// $2 = sequence number, $3 = clipboard data. the sequence number +// $2 = sequence number, $3 = mark $4 = clipboard data. the sequence number // is 0 when sent by the primary. secondary screens should use the // sequence number from the most recent kMsgCEnter. $1 = clipboard // identifier. diff --git a/src/test/integtests/net/NetworkTests.cpp b/src/test/integtests/net/NetworkTests.cpp index 94d9cac0..fb358bde 100644 --- a/src/test/integtests/net/NetworkTests.cpp +++ b/src/test/integtests/net/NetworkTests.cpp @@ -420,7 +420,7 @@ NetworkTests::sendMockData(void* eventTarget) FileChunker::FileChunk* sizeMessage = new FileChunker::FileChunk(sizeLength + 2); char* chunkData = sizeMessage->m_chunk; - chunkData[0] = kFileStart; + chunkData[0] = kDataStart; memcpy(&chunkData[1], size.c_str(), sizeLength); chunkData[sizeLength + 1] = '\0'; m_events.addEvent(Event(m_events.forIScreen().fileChunkSending(), eventTarget, sizeMessage)); @@ -440,7 +440,7 @@ NetworkTests::sendMockData(void* eventTarget) FileChunker::FileChunk* fileChunk = new FileChunker::FileChunk(chunkSize + 2); char* chunkData = fileChunk->m_chunk; - chunkData[0] = kFileChunk; + chunkData[0] = kDataChunk; memcpy(&chunkData[1], &m_mockData[sentLength], chunkSize); chunkData[chunkSize + 1] = '\0'; m_events.addEvent(Event(m_events.forIScreen().fileChunkSending(), eventTarget, fileChunk)); @@ -458,7 +458,7 @@ NetworkTests::sendMockData(void* eventTarget) FileChunker::FileChunk* transferFinished = new FileChunker::FileChunk(2); chunkData = transferFinished->m_chunk; - chunkData[0] = kFileEnd; + chunkData[0] = kDataEnd; chunkData[1] = '\0'; m_events.addEvent(Event(m_events.forIScreen().fileChunkSending(), eventTarget, transferFinished)); }