summaryrefslogtreecommitdiffstats
path: root/src/lib/barrier/StreamChunker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/barrier/StreamChunker.cpp')
-rw-r--r--src/lib/barrier/StreamChunker.cpp166
1 files changed, 166 insertions, 0 deletions
diff --git a/src/lib/barrier/StreamChunker.cpp b/src/lib/barrier/StreamChunker.cpp
new file mode 100644
index 0000000..8b8971c
--- /dev/null
+++ b/src/lib/barrier/StreamChunker.cpp
@@ -0,0 +1,166 @@
+/*
+ * barrier -- mouse and keyboard sharing utility
+ * Copyright (C) 2013-2016 Symless 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 LICENSE 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 "barrier/StreamChunker.h"
+
+#include "mt/Lock.h"
+#include "mt/Mutex.h"
+#include "barrier/FileChunk.h"
+#include "barrier/ClipboardChunk.h"
+#include "barrier/protocol_types.h"
+#include "base/EventTypes.h"
+#include "base/Event.h"
+#include "base/IEventQueue.h"
+#include "base/EventTypes.h"
+#include "base/Log.h"
+#include "base/Stopwatch.h"
+#include "base/String.h"
+#include "common/stdexcept.h"
+
+#include <fstream>
+
+using namespace std;
+
+static const size_t g_chunkSize = 32 * 1024; //32kb
+
+bool StreamChunker::s_isChunkingFile = false;
+bool StreamChunker::s_interruptFile = false;
+Mutex* StreamChunker::s_interruptMutex = NULL;
+
+void
+StreamChunker::sendFile(
+ char* filename,
+ IEventQueue* events,
+ void* eventTarget)
+{
+ s_isChunkingFile = true;
+
+ std::fstream file(static_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)
+ String fileSize = barrier::string::sizeTypeToString(size);
+ FileChunk* sizeMessage = FileChunk::start(fileSize);
+
+ events->addEvent(Event(events->forFile().fileChunkSending(), eventTarget, sizeMessage));
+
+ // send chunk messages with a fixed chunk size
+ size_t sentLength = 0;
+ size_t chunkSize = g_chunkSize;
+ file.seekg (0, std::ios::beg);
+
+ while (true) {
+ if (s_interruptFile) {
+ s_interruptFile = false;
+ LOG((CLOG_DEBUG "file transmission interrupted"));
+ break;
+ }
+
+ events->addEvent(Event(events->forFile().keepAlive(), eventTarget));
+
+ // make sure we don't read too much from the mock data.
+ if (sentLength + chunkSize > size) {
+ chunkSize = size - sentLength;
+ }
+
+ char* chunkData = new char[chunkSize];
+ file.read(chunkData, chunkSize);
+ UInt8* data = reinterpret_cast<UInt8*>(chunkData);
+ FileChunk* fileChunk = FileChunk::data(data, chunkSize);
+ delete[] chunkData;
+
+ events->addEvent(Event(events->forFile().fileChunkSending(), eventTarget, fileChunk));
+
+ sentLength += chunkSize;
+ file.seekg (sentLength, std::ios::beg);
+
+ if (sentLength == size) {
+ break;
+ }
+ }
+
+ // send last message
+ FileChunk* end = FileChunk::end();
+
+ events->addEvent(Event(events->forFile().fileChunkSending(), eventTarget, end));
+
+ file.close();
+
+ s_isChunkingFile = false;
+}
+
+void
+StreamChunker::sendClipboard(
+ String& data,
+ size_t size,
+ ClipboardID id,
+ UInt32 sequence,
+ IEventQueue* events,
+ void* eventTarget)
+{
+ // send first message (data size)
+ String dataSize = barrier::string::sizeTypeToString(size);
+ ClipboardChunk* sizeMessage = ClipboardChunk::start(id, sequence, dataSize);
+
+ events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, sizeMessage));
+
+ // send clipboard chunk with a fixed size
+ size_t sentLength = 0;
+ size_t chunkSize = g_chunkSize;
+
+ while (true) {
+ events->addEvent(Event(events->forFile().keepAlive(), eventTarget));
+
+ // 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);
+ ClipboardChunk* dataChunk = ClipboardChunk::data(id, sequence, chunk);
+
+ events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, dataChunk));
+
+ sentLength += chunkSize;
+ if (sentLength == size) {
+ break;
+ }
+ }
+
+ // send last message
+ ClipboardChunk* end = ClipboardChunk::end(id, sequence);
+
+ events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, end));
+
+ LOG((CLOG_DEBUG "sent clipboard size=%d", sentLength));
+}
+
+void
+StreamChunker::interruptFile()
+{
+ if (s_isChunkingFile) {
+ s_interruptFile = true;
+ LOG((CLOG_INFO "previous dragged file has become invalid"));
+ }
+}