Send clipboard data in small chunks without using thread #4601

This commit is contained in:
Jerry (Xinyu Hou) 2015-05-15 14:26:57 -07:00 committed by Xinyu Hou
parent 08aee6cba7
commit 44089d55e8
7 changed files with 137 additions and 45 deletions

View File

@ -545,22 +545,33 @@ void
ServerProxy::setClipboard() ServerProxy::setClipboard()
{ {
// parse // parse
static String dataCached;
ClipboardID id; ClipboardID id;
UInt32 seqNum; UInt32 seqNum;
size_t mark = 0;
String data; String data;
ProtocolUtil::readf(m_stream, kMsgDClipboard + 4, &id, &seqNum, &data); ProtocolUtil::readf(m_stream, kMsgDClipboard + 4, &id, &seqNum, &mark, &data);
LOG((CLOG_DEBUG "recv clipboard %d size=%d", id, data.size()));
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 // validate
if (id >= kClipboardEnd) { if (id >= kClipboardEnd) {
return; return;
} }
// forward // forward
Clipboard clipboard; Clipboard clipboard;
clipboard.unmarshall(data, 0); clipboard.unmarshall(dataCached, 0);
m_client->setClipboard(id, &clipboard); m_client->setClipboard(id, &clipboard);
} }
}
void void
ServerProxy::grabClipboard() ServerProxy::grabClipboard()
@ -857,7 +868,7 @@ ServerProxy::fileChunkReceived()
ProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content); ProtocolUtil::readf(m_stream, kMsgDFileTransfer + 4, &mark, &content);
switch (mark) { switch (mark) {
case kFileStart: case kDataStart:
m_client->clearReceivedFileData(); m_client->clearReceivedFileData();
m_client->setExpectedFileSize(content); m_client->setExpectedFileSize(content);
if (CLOG->getFilter() >= kDEBUG2) { if (CLOG->getFilter() >= kDEBUG2) {
@ -866,7 +877,7 @@ ServerProxy::fileChunkReceived()
} }
break; break;
case kFileChunk: case kDataChunk:
m_client->fileChunkReceived(content); m_client->fileChunkReceived(content);
if (CLOG->getFilter() >= kDEBUG2) { if (CLOG->getFilter() >= kDEBUG2) {
LOG((CLOG_DEBUG2 "recv file data from server: size=%i", content.size())); LOG((CLOG_DEBUG2 "recv file data from server: size=%i", content.size()));
@ -884,7 +895,7 @@ ServerProxy::fileChunkReceived()
} }
break; break;
case kFileEnd: case kDataEnd:
m_events->addEvent(Event(m_events->forIScreen().fileRecieveCompleted(), m_client)); m_events->addEvent(Event(m_events->forIScreen().fileRecieveCompleted(), m_client));
if (CLOG->getFilter() >= kDEBUG2) { if (CLOG->getFilter() >= kDEBUG2) {
LOG((CLOG_DEBUG2 "file data transfer finished")); LOG((CLOG_DEBUG2 "file data transfer finished"));
@ -915,15 +926,15 @@ ServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
String chunk(data, dataSize); String chunk(data, dataSize);
switch (mark) { switch (mark) {
case kFileStart: case kDataStart:
LOG((CLOG_DEBUG2 "file sending start: size=%s", data)); LOG((CLOG_DEBUG2 "file sending start: size=%s", data));
break; break;
case kFileChunk: case kDataChunk:
LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size())); LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size()));
break; break;
case kFileEnd: case kDataEnd:
LOG((CLOG_DEBUG2 "file sending finished")); LOG((CLOG_DEBUG2 "file sending finished"));
break; break;
} }

View File

@ -18,12 +18,15 @@
#include "server/ClientProxy1_5.h" #include "server/ClientProxy1_5.h"
#include "server/Server.h" #include "server/Server.h"
#include "synergy/FileChunker.h"
#include "synergy/ProtocolUtil.h" #include "synergy/ProtocolUtil.h"
#include "mt/Thread.h" #include "mt/Thread.h"
#include "io/IStream.h" #include "io/IStream.h"
#include "base/TMethodJob.h" #include "base/TMethodJob.h"
#include "base/Log.h" #include "base/Log.h"
#include <sstream>
// //
// ClientProxy1_5 // ClientProxy1_5
// //
@ -57,15 +60,15 @@ ClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize)
String chunk(data, dataSize); String chunk(data, dataSize);
switch (mark) { switch (mark) {
case kFileStart: case kDataStart:
LOG((CLOG_DEBUG2 "file sending start: size=%s", data)); LOG((CLOG_DEBUG2 "file sending start: size=%s", data));
break; break;
case kFileChunk: case kDataChunk:
LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size())); LOG((CLOG_DEBUG2 "file chunk sending: size=%i", chunk.size()));
break; break;
case kFileEnd: case kDataEnd:
LOG((CLOG_DEBUG2 "file sending finished")); LOG((CLOG_DEBUG2 "file sending finished"));
break; break;
} }
@ -82,12 +85,50 @@ ClientProxy1_5::setClipboard(ClipboardID id, const IClipboard* clipboard)
m_clipboard[id].m_dirty = false; m_clipboard[id].m_dirty = false;
Clipboard::copy(&m_clipboard[id].m_clipboard, clipboard); 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( size_t size = data.size();
new TMethodJob<ClientProxy1_5>( LOG((CLOG_DEBUG "sending clipboard %d to \"%s\" size=%d", id, getName().c_str(), size));
this, &ClientProxy1_5::sendClipboardThread,
reinterpret_cast<void*>(id))); //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<ClientProxy1_5>(
// this, &ClientProxy1_5::sendClipboardThread,
// reinterpret_cast<void*>(id)));
} }
} }
@ -117,7 +158,7 @@ ClientProxy1_5::fileChunkReceived()
Server* server = getServer(); Server* server = getServer();
switch (mark) { switch (mark) {
case kFileStart: case kDataStart:
server->clearReceivedFileData(); server->clearReceivedFileData();
server->setExpectedFileSize(content); server->setExpectedFileSize(content);
if (CLOG->getFilter() >= kDEBUG2) { if (CLOG->getFilter() >= kDEBUG2) {
@ -126,7 +167,7 @@ ClientProxy1_5::fileChunkReceived()
} }
break; break;
case kFileChunk: case kDataChunk:
server->fileChunkReceived(content); server->fileChunkReceived(content);
if (CLOG->getFilter() >= kDEBUG2) { if (CLOG->getFilter() >= kDEBUG2) {
LOG((CLOG_DEBUG2 "recv file data from client: chunck size=%i", content.size())); LOG((CLOG_DEBUG2 "recv file data from client: chunck size=%i", content.size()));
@ -144,7 +185,7 @@ ClientProxy1_5::fileChunkReceived()
} }
break; break;
case kFileEnd: case kDataEnd:
m_events->addEvent(Event(m_events->forIScreen().fileRecieveCompleted(), server)); m_events->addEvent(Event(m_events->forIScreen().fileRecieveCompleted(), server));
if (CLOG->getFilter() >= kDEBUG2) { if (CLOG->getFilter() >= kDEBUG2) {
LOG((CLOG_DEBUG2 "file data transfer finished")); LOG((CLOG_DEBUG2 "file data transfer finished"));
@ -172,7 +213,48 @@ ClientProxy1_5::dragInfoReceived()
void void
ClientProxy1_5::sendClipboardThread(void* data) ClientProxy1_5::sendClipboardThread(void* data)
{ {
size_t id = reinterpret_cast<size_t>(data); //size_t id = reinterpret_cast<size_t>(data);
LOG((CLOG_DEBUG "sending clipboard %d to \"%s\" size=%d", id, getName().c_str(), m_clipboardData.size())); //String clipboardData = m_clipboardData.at(id);
ProtocolUtil::writef(getStream(), kMsgDClipboard, id, 0, &m_clipboardData); //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");
} }

View File

@ -19,6 +19,7 @@
#include "server/ClientProxy1_4.h" #include "server/ClientProxy1_4.h"
#include "base/Stopwatch.h" #include "base/Stopwatch.h"
#include "common/stdvector.h"
class Server; class Server;
class IEventQueue; class IEventQueue;
@ -48,6 +49,5 @@ private:
double m_elapsedTime; double m_elapsedTime;
size_t m_receivedDataSize; size_t m_receivedDataSize;
static const UInt16 m_intervalThreshold; static const UInt16 m_intervalThreshold;
Thread* m_sendFileThread; //Thread* m_sendFileThread;
String m_clipboardData;
}; };

View File

@ -54,7 +54,7 @@ FileChunker::sendFileChunks(char* filename, IEventQueue* events, void* eventTarg
FileChunk* sizeMessage = new FileChunk(sizeLength + 2); FileChunk* sizeMessage = new FileChunk(sizeLength + 2);
char* chunkData = sizeMessage->m_chunk; char* chunkData = sizeMessage->m_chunk;
chunkData[0] = kFileStart; chunkData[0] = kDataStart;
memcpy(&chunkData[1], fileSize.c_str(), sizeLength); memcpy(&chunkData[1], fileSize.c_str(), sizeLength);
chunkData[sizeLength + 1] = '\0'; chunkData[sizeLength + 1] = '\0';
events->addEvent(Event(events->forIScreen().fileChunkSending(), eventTarget, sizeMessage)); 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); FileChunk* fileChunk = new FileChunk(chunkSize + 2);
char* chunkData = fileChunk->m_chunk; char* chunkData = fileChunk->m_chunk;
chunkData[0] = kFileChunk; chunkData[0] = kDataChunk;
file.read(&chunkData[1], chunkSize); file.read(&chunkData[1], chunkSize);
chunkData[chunkSize + 1] = '\0'; chunkData[chunkSize + 1] = '\0';
events->addEvent(Event(events->forIScreen().fileChunkSending(), eventTarget, fileChunk)); 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); FileChunk* transferFinished = new FileChunk(2);
chunkData = transferFinished->m_chunk; chunkData = transferFinished->m_chunk;
chunkData[0] = kFileEnd; chunkData[0] = kDataEnd;
chunkData[1] = '\0'; chunkData[1] = '\0';
events->addEvent(Event(events->forIScreen().fileChunkSending(), eventTarget, transferFinished)); events->addEvent(Event(events->forIScreen().fileChunkSending(), eventTarget, transferFinished));

View File

@ -41,7 +41,7 @@ const char* kMsgDMouseMove = "DMMV%2i%2i";
const char* kMsgDMouseRelMove = "DMRM%2i%2i"; const char* kMsgDMouseRelMove = "DMRM%2i%2i";
const char* kMsgDMouseWheel = "DMWM%2i%2i"; const char* kMsgDMouseWheel = "DMWM%2i%2i";
const char* kMsgDMouseWheel1_0 = "DMWM%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* kMsgDInfo = "DINF%2i%2i%2i%2i%2i%2i%2i";
const char* kMsgDSetOptions = "DSOP%4I"; const char* kMsgDSetOptions = "DSOP%4I";
const char* kMsgDFileTransfer = "DFTR%1i%s"; const char* kMsgDFileTransfer = "DFTR%1i%s";

View File

@ -70,13 +70,12 @@ enum EDirectionMask {
}; };
// file transfer constants // file transfer constants
enum EFileTransfer { enum EDataTransfer {
kFileStart = 1, kDataStart = 1,
kFileChunk = 2, kDataChunk = 2,
kFileEnd = 3 kDataEnd = 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
// refers to the n'th argument (counting from one). message codes are // 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; extern const char* kMsgDMouseWheel1_0;
// clipboard data: primary <-> secondary // 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 // is 0 when sent by the primary. secondary screens should use the
// sequence number from the most recent kMsgCEnter. $1 = clipboard // sequence number from the most recent kMsgCEnter. $1 = clipboard
// identifier. // identifier.

View File

@ -420,7 +420,7 @@ NetworkTests::sendMockData(void* eventTarget)
FileChunker::FileChunk* sizeMessage = new FileChunker::FileChunk(sizeLength + 2); FileChunker::FileChunk* sizeMessage = new FileChunker::FileChunk(sizeLength + 2);
char* chunkData = sizeMessage->m_chunk; char* chunkData = sizeMessage->m_chunk;
chunkData[0] = kFileStart; chunkData[0] = kDataStart;
memcpy(&chunkData[1], size.c_str(), sizeLength); memcpy(&chunkData[1], size.c_str(), sizeLength);
chunkData[sizeLength + 1] = '\0'; chunkData[sizeLength + 1] = '\0';
m_events.addEvent(Event(m_events.forIScreen().fileChunkSending(), eventTarget, sizeMessage)); 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); FileChunker::FileChunk* fileChunk = new FileChunker::FileChunk(chunkSize + 2);
char* chunkData = fileChunk->m_chunk; char* chunkData = fileChunk->m_chunk;
chunkData[0] = kFileChunk; chunkData[0] = kDataChunk;
memcpy(&chunkData[1], &m_mockData[sentLength], chunkSize); memcpy(&chunkData[1], &m_mockData[sentLength], chunkSize);
chunkData[chunkSize + 1] = '\0'; chunkData[chunkSize + 1] = '\0';
m_events.addEvent(Event(m_events.forIScreen().fileChunkSending(), eventTarget, fileChunk)); 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); FileChunker::FileChunk* transferFinished = new FileChunker::FileChunk(2);
chunkData = transferFinished->m_chunk; chunkData = transferFinished->m_chunk;
chunkData[0] = kFileEnd; chunkData[0] = kDataEnd;
chunkData[1] = '\0'; chunkData[1] = '\0';
m_events.addEvent(Event(m_events.forIScreen().fileChunkSending(), eventTarget, transferFinished)); m_events.addEvent(Event(m_events.forIScreen().fileChunkSending(), eventTarget, transferFinished));
} }