Files
UE_SpaceStudio/InteractiveControl/Plugins/SimpleUDPTCPSocketClient/Source/SocketClient/Private/SocketClientTCPFileHandlerThread.cpp
T

592 lines
22 KiB
C++

// Copyright 2022 David Romanski (Socke). All Rights Reserved.
#include "SocketClientTCPFileHandlerThread.h"
FSocketClientTCPFileHandlerThread::FSocketClientTCPFileHandlerThread(USocketClientBPLibrary* socketClientP, FString clientConnectionIDP, FString ipOrDomainP, ESocketClientIPType ipTypeP, int32 portP, USocketClientTCPClient* tcpClientP) :
socketClient(socketClientP),
clientConnectionID(clientConnectionIDP),
ipOrDomain(ipOrDomainP),
ipType(ipTypeP),
port(portP),
tcpClient(tcpClientP) {
FString threadName = "FServerFileConnectionThread" + FGuid::NewGuid().ToString();
thread = FRunnableThread::Create(this, *threadName, 0, EThreadPriority::TPri_Normal);
}
FSocketClientTCPFileHandlerThread::~FSocketClientTCPFileHandlerThread() {
delete thread;
}
uint32 FSocketClientTCPFileHandlerThread::Run() {
//UE_LOG(LogTemp, Display, TEXT("DoWork:%s"),*(FDateTime::Now()).ToString());
FString ip = socketClient->resolveDomain(ipOrDomain, ipType);
int32 portGlobal = port;
FString clientConnectionIDGlobal = clientConnectionID;
USocketClientBPLibrary* socketClientGlobal = socketClient;
USocketClientTCPClient* tcpClientGlobal = tcpClient;
//UE_LOG(LogTemp, Warning, TEXT("Tread:%s:%i"),*ip, port);
ISocketSubsystem* sSS = USocketClientBPLibrary::getSocketSubSystem();
if (sSS == nullptr) {
AsyncTask(ENamedThreads::GameThread, [ip, portGlobal, clientConnectionIDGlobal, socketClientGlobal, tcpClientGlobal]() {
if (socketClientGlobal != nullptr)
socketClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(false, "Connection failed(1). SocketSubSystem does not exist." + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal, clientConnectionIDGlobal);
if (tcpClientGlobal != nullptr)
tcpClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(false, "Connection failed(1). SocketSubSystem does not exist." + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal, clientConnectionIDGlobal);
});
return 0;
}
TSharedRef<FInternetAddr> addr = sSS->CreateInternetAddr();
bool bIsValid;
addr->SetIp(*ip, bIsValid);
addr->SetPort(port);
if (bIsValid) {
// create the socket
FSocket* socket = sSS->CreateSocket(NAME_Stream, TEXT("socketClient"), addr->GetProtocolType());
tcpClient->setSocket(socket);
// try to connect to the server
if (socket == nullptr || socket->Connect(*addr) == false) {
const TCHAR* socketErr = sSS->GetSocketError(SE_GET_LAST_ERROR_CODE);
AsyncTask(ENamedThreads::GameThread, [ip, portGlobal, clientConnectionIDGlobal, socketClientGlobal, tcpClientGlobal, socketErr]() {
if (socketClientGlobal != nullptr)
socketClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(false, "Connection failed(2):" + FString(socketErr) + "|" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal, clientConnectionIDGlobal);
if (tcpClientGlobal != nullptr)
tcpClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(false, "Connection failed(2):" + FString(socketErr) + "|" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal, clientConnectionIDGlobal);
});
}
else {
//connected
AsyncTask(ENamedThreads::GameThread, [ip, portGlobal, clientConnectionIDGlobal, tcpClientGlobal, socketClientGlobal]() {
if (socketClientGlobal != nullptr)
socketClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(true, "Connection successful:" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal, clientConnectionIDGlobal);
if (tcpClientGlobal != nullptr)
tcpClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(true, "Connection successful:" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal, clientConnectionIDGlobal);
});
tcpClient->setRun(true);
if (tcpClient->isReceiveFile()) {
doRequestFileFromServer(socket);
}
else {
if (tcpClient->isSendFile()) {
doSendFileToServer(socket);
}
}
}
AsyncTask(ENamedThreads::GameThread, [ip, portGlobal, clientConnectionIDGlobal, tcpClientGlobal, socketClientGlobal]() {
if (socketClientGlobal != nullptr) {
socketClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(false, "Connection close:" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal, clientConnectionIDGlobal);
if (tcpClientGlobal != nullptr)
tcpClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(false, "Connection close:" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal, clientConnectionIDGlobal);
}
});
USocketClientBPLibrary::getSocketClientTarget()->closeSocketClientConnectionTCPNonStatic(clientConnectionID);
tcpClient->setRun(false);
if (socket != nullptr) {
socket->Close();
}
}
else {
AsyncTask(ENamedThreads::GameThread, [ip, portGlobal, clientConnectionIDGlobal, tcpClientGlobal, socketClientGlobal]() {
if (socketClientGlobal != nullptr)
socketClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(false, "Connection failed(3). IP not valid:" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal, clientConnectionIDGlobal);
if (tcpClientGlobal != nullptr)
tcpClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(false, "Connection failed(3). IP not valid:" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal, clientConnectionIDGlobal);
});
}
return 0;
}
void FSocketClientTCPFileHandlerThread::doRequestFileFromServer(FSocket* socket){
FString filePath = tcpClient->getFilePath();
if (!FPaths::DirectoryExists(filePath)) {
triggerFileTransferOverTCPInfoEvent("Data transmission aborted. Directory not found.", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
return;
}
FString message = "REQUEST_FILE_FROM_SERVER_|_" + tcpClient->getFileToken();
sendMessageToServer(message, socket);
message = readMessageFromServer(socket);
if (message.StartsWith("REQUEST_FILE_FROM_SERVER_ACCEPTED_|_" + tcpClient->getFileToken())) {
TArray<FString> lines;
message.ParseIntoArray(lines, TEXT("_|_"), true);
if (lines.Num() == 5) {
if (lines[0].Equals("REQUEST_FILE_FROM_SERVER_ACCEPTED") && lines[1].Len() > 0 && lines[2].Len() > 0 && lines[3].Len() > 0 && lines[4].Len() > 0) {
FArchive* writer = nullptr;
FString md5Server = lines[2];
int64 fileSize = FCString::Atoi64(*lines[3]);
if (filePath.EndsWith("/")) {
filePath += lines[4];
}
else {
filePath += "/" + lines[4];
}
int64 fileSizeOnClient = 0;
if (FPaths::FileExists(filePath)) {
fileSizeOnClient = tcpClient->fileSize(filePath);
if (tcpClient->hasResume()) {
writer = IFileManager::Get().CreateFileWriter(*filePath, EFileWrite::FILEWRITE_Append);
}
else {
writer = IFileManager::Get().CreateFileWriter(*filePath);
}
}
else {
writer = IFileManager::Get().CreateFileWriter(*filePath);
}
if (writer == nullptr) {
triggerFileTransferOverTCPInfoEvent("File could not be created. ", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
return;
}
if (writer->TotalSize() >= fileSize) {
writer->Close();
delete writer;
triggerFileTransferOverTCPInfoEvent("File on the client has the same size or is larger than the file on the server.", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
return;
}
//downloadFile = true;
int64 bytesDownloaded = writer->TotalSize();
message = "REQUEST_FILE_FROM_SERVER_ACCEPTED_|_" + tcpClient->getFileToken() + "_|_" + tcpClient->int64ToString(bytesDownloaded);
sendMessageToServer(message, socket);
int64 lastTimeWithData = 0;
int64 ticks1 = 0;
int64 ticks2 = 0;
int64 ticksDownload = 0;
int64 lastByte = 0;
uint32 dataSize = 0;
TArray<uint8> buffer;
while (socket != nullptr && tcpClient->isRun()) {
ticks1 = FDateTime::Now().GetTicks();
socket->Wait(ESocketWaitConditions::WaitForRead, FTimespan::FromSeconds(waitForRead));
ticks2 = FDateTime::Now().GetTicks();
bool hasData = socket->HasPendingData(dataSize);
if (!hasData && ticks1 == ticks2) {
triggerFileTransferOverTCPInfoEvent("Connection broken.", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
break;
}
// UE_LOG(LogTemp, Display, TEXT("download %i"),dataSize);
if (hasData) {
lastTimeWithData = FDateTime::Now().GetTicks();
//downlnoad
int32 bytesRead = 0;
buffer.Empty();
buffer.SetNumUninitialized(dataSize);
if (socket->Recv(buffer.GetData(), buffer.Num(), bytesRead)) {
writer->Serialize(buffer.GetData(), buffer.Num());
//show progress each second
if ((ticksDownload + 10000000) <= FDateTime::Now().GetTicks()) {
writer->Flush();
int64 bytesTransferredLastSecond = bytesDownloaded - lastByte;
//float speed = ((float)bytesTransferredLastSecond) / 125000;
float mbit = ((float)bytesTransferredLastSecond) / 1024 / 1024 * 8;
float sent = ((float)bytesDownloaded) / 1048576;
float left = 0;
float percent = 0;
if (fileSize > 0) {
left = ((float)(fileSize - bytesDownloaded)) / 1048576;
percent = ((float)bytesDownloaded / (float)fileSize * 100);
}
triggerTransferFileEvent(clientConnectionID, filePath, socketClient, tcpClient, percent, mbit, bytesDownloaded, fileSize);
ticksDownload = FDateTime::Now().GetTicks();
lastByte = bytesDownloaded;
}
bytesDownloaded += bytesRead;
}
if (bytesDownloaded >= fileSize) {
if (writer != nullptr) {
writer->Close();
delete writer;
writer = nullptr;
}
sendEndMessage(filePath, tcpClient->getFileToken(), md5Server, clientConnectionID, socket, socketClient, tcpClient);
//transfer file finish
triggerTransferFileEvent(clientConnectionID, filePath, socketClient, tcpClient, 100, 0, bytesDownloaded, fileSize);
tcpClient->setRun(false);
}
}
//no data time out
else {
//one second = 10000000 ticks
//5 seconds timeout
// UE_LOG(LogTemp, Display, TEXT("timeout %i"),(FDateTime::Now().GetTicks() - lastTimeWithData));
if ((FDateTime::Now().GetTicks() - lastTimeWithData) >= 50000000) {
triggerFileTransferOverTCPInfoEvent("Connection timeout", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
break;
}
}
}
buffer.Empty();
if (writer != nullptr) {
writer->Close();
delete writer;
writer = nullptr;
}
}
}
}
}
void FSocketClientTCPFileHandlerThread::doSendFileToServer(FSocket* socket){
FString filePath = tcpClient->getFilePath();
if (!FPaths::FileExists(filePath)) {
triggerFileTransferOverTCPInfoEvent("Data transmission aborted. File not found.", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
return;
}
int64 fileSize = tcpClient->fileSize(filePath);
bool md5okay = false;
FString md5 = FString();
tcpClient->getMD5FromFileAbsolutePath(filePath, md5okay, md5);
FString fileAuthMessage = "SEND_FILE_TO_SERVER_|_" + tcpClient->getFileToken() + "_|_" + md5 + "_|_" + FPaths::GetCleanFilename(filePath) + "_|_" + tcpClient->int64ToString(fileSize);
sendMessageToServer(fileAuthMessage, socket);
FString message = readMessageFromServer(socket);
if (message.StartsWith("SEND_FILE_TO_SERVER_ACCEPTED_|_" + tcpClient->getFileToken())) {
if (message.RemoveFromStart("SEND_FILE_TO_SERVER_ACCEPTED_|_" + tcpClient->getFileToken() + "_|_")) {
int64 startPosition = FCString::Atoi64(*message);
// upload file
FArchive* reader = IFileManager::Get().CreateFileReader(*filePath);
if (reader == nullptr || reader->TotalSize() == 0) {
if (reader != nullptr) {
reader->Close();
}
tcpClient->setRun(false);
return;
}
fileSize = reader->TotalSize();
/*int64 ticks1 = 0;
int64 ticks2 = 0;*/
int64 readSize = 0;
int64 lastPosition = startPosition;
int64 bytesSentSinceLastTick = 0;
int32 bufferSize = 1024 * 64;
int32 dataSendBySocket = 0;
float percent = 0.f;
float mbit = 0.f;
TArray<uint8> buffer;
int64 lastTimeTicks = FDateTime::Now().GetTicks();
if (bufferSize > fileSize) {
bufferSize = fileSize;
}
if (lastPosition > 0) {
reader->Seek(lastPosition);
}
while (tcpClient->isRun() && lastPosition < fileSize) {
if ((lastPosition + bufferSize) > fileSize) {
bufferSize = fileSize - lastPosition;
}
//buffer.Reset(bufferSize);
buffer.Empty();
buffer.AddUninitialized(bufferSize);
reader->Serialize(buffer.GetData(), buffer.Num());
lastPosition += buffer.Num();
//UE_LOG(LogTemp, Warning, TEXT("Send: %i"),buffer.Num());
//ticks1 = FDateTime::Now().GetTicks();
socket->Send(buffer.GetData(), buffer.Num(), dataSendBySocket);
//socket->Wait(ESocketWaitConditions::WaitForWrite, FTimespan::FromSeconds(0.001));
//ticks2 = FDateTime::Now().GetTicks();
if (dataSendBySocket == 0 || dataSendBySocket != buffer.Num()) {
triggerFileTransferOverTCPInfoEvent("Data transmission aborted. Connection possibly broken.", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
return;
}
//slowdown for tests
//FPlatformProcess::Sleep(0.01f);
//fire event every second
//one second = 10000000 ticks
if (((FDateTime::Now().GetTicks()) - lastTimeTicks) >= 10000000) {
mbit = ((float)lastPosition - (float)bytesSentSinceLastTick) / 1024 / 1024 * 8;
lastTimeTicks = FDateTime::Now().GetTicks();
bytesSentSinceLastTick = lastPosition;
percent = ((float)lastPosition / fileSize) * 100;
triggerTransferFileEvent(clientConnectionID, filePath, socketClient, tcpClient, percent, mbit, lastPosition, fileSize);
}
}
mbit = ((float)lastPosition - (float)bytesSentSinceLastTick) / 1024 / 1024 * 8;
percent = ((float)lastPosition / fileSize) * 100;
triggerTransferFileEvent(clientConnectionID, filePath, socketClient, tcpClient, percent, mbit, lastPosition, fileSize);
buffer.Empty();
if (reader != nullptr) {
reader->Close();
reader = nullptr;
}
message = readMessageFromServer(socket);
if (message.StartsWith("SEND_FILE_TO_SERVER_END_|_" + tcpClient->getFileToken())) {
if (message.RemoveFromStart("SEND_FILE_TO_SERVER_END_|_" + tcpClient->getFileToken() + "_|_")) {
if (message.Equals("OKAY")) {
triggerFileTransferOverTCPInfoEvent("Data transmission successful. ", clientConnectionID, filePath, true, socketClient, tcpClient);
tcpClient->setRun(false);
}
else {
triggerFileTransferOverTCPInfoEvent("There was an error during data transmission. File may be corrupted or incomplete. ", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
}
}
else {
triggerFileTransferOverTCPInfoEvent("Data transmission aborted. Wrong answer from the server (3). ", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
}
}
}
else {
triggerFileTransferOverTCPInfoEvent("Data transmission aborted. Wrong answer from the server (2). ", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
return;
}
}
else {
if (message.StartsWith("SEND_FILE_TO_SERVER_END_|_" + tcpClient->getFileToken())) {
if (message.RemoveFromStart("SEND_FILE_TO_SERVER_END_|_" + tcpClient->getFileToken() + "_|_")) {
if (message.Equals("OKAY")) {
triggerFileTransferOverTCPInfoEvent("Data transmission successful. ", clientConnectionID, filePath, true, socketClient, tcpClient);
tcpClient->setRun(false);
}
else {
triggerFileTransferOverTCPInfoEvent("There was an error during data transmission. File may be corrupted or incomplete. ", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
}
}
else {
triggerFileTransferOverTCPInfoEvent("Data transmission aborted. Wrong answer from the server (3). ", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
}
}
else {
triggerFileTransferOverTCPInfoEvent("Data transmission aborted. Wrong answer from the server (1). ", clientConnectionID, filePath, false, socketClient, tcpClient);
tcpClient->setRun(false);
}
}
}
void FSocketClientTCPFileHandlerThread::sendMessageToServer(FString message, FSocket* socket){
message = tcpClient->encryptMessage(message);
TArray<uint8> byteCache;
FTCHARToUTF8 Convert(*message);
int32 sent = 0;
if (FGenericPlatformProperties::IsLittleEndian()) {
byteCache.Add(0x00);
}
else {
byteCache.Add(0x01);
}
byteCache.SetNum(5);
int32 dataLength = Convert.Length();
FMemory::Memcpy(byteCache.GetData() + 1, &dataLength, 4);
byteCache.Append((uint8*)Convert.Get(), Convert.Length());
socket->Send(byteCache.GetData(), byteCache.Num(), sent);
byteCache.Empty();
}
void FSocketClientTCPFileHandlerThread::triggerFileTransferOverTCPInfoEvent(FString messageP, FString clientConnectionIDP, FString filePathP, bool successP, USocketClientBPLibrary* socketClientP, USocketClientTCPClient* tcpClientP) {
AsyncTask(ENamedThreads::GameThread, [messageP, clientConnectionIDP, filePathP, successP, socketClientP, tcpClientP]() {
if (socketClientP != nullptr)
socketClientP->onfileTransferOverTCPInfoEventDelegate.Broadcast(messageP, clientConnectionIDP, filePathP, successP);
if (tcpClientP != nullptr)
tcpClientP->onfileTransferOverTCPInfoEventDelegate.Broadcast(messageP, clientConnectionIDP, filePathP, successP);
});
}
void FSocketClientTCPFileHandlerThread::triggerTransferFileEvent(FString clientConnectionIDP, FString filePathP, USocketClientBPLibrary* socketClientP, USocketClientTCPClient* tcpClientP, float percentP, float mbitP, int64 transferredP, int64 fileSizeP) {
AsyncTask(ENamedThreads::GameThread, [clientConnectionIDP, socketClientP, filePathP, tcpClientP, percentP, mbitP, transferredP, fileSizeP]() {
if (socketClientP != nullptr)
socketClientP->ontransferFileOverTCPProgressEventDelegate.Broadcast(clientConnectionIDP, filePathP, percentP, mbitP, transferredP, fileSizeP);
if (tcpClientP != nullptr)
tcpClientP->ontransferFileOverTCPProgressEventDelegate.Broadcast(clientConnectionIDP, filePathP, percentP, mbitP, transferredP, fileSizeP);
});
}
void FSocketClientTCPFileHandlerThread::sendEndMessage(FString fullFilePathP, FString tokenP, FString md5ServerP, FString clientConnectionIDP, FSocket* clientSocketP, USocketClientBPLibrary* socketClientP, USocketClientTCPClient* tcpClientP) {
bool md5okay = false;
FString md5Client = FString();
tcpClientP->getMD5FromFileAbsolutePath(fullFilePathP, md5okay, md5Client);
FString response = "REQUEST_FILE_FROM_SERVER_END_|_" + tokenP + "_|_";
if (md5okay && md5ServerP.Equals(md5Client)) {
triggerFileTransferOverTCPInfoEvent("File successfully received.", clientConnectionIDP, fullFilePathP, true, socketClientP, tcpClientP);
response += "OKAY";
}
else {
triggerFileTransferOverTCPInfoEvent("File received but MD5 does not match. Corrupted file will be deleted if resume is not disabled.", clientConnectionIDP, fullFilePathP, false, socketClientP, tcpClientP);
response += "MD5ERROR";
if (tcpClientP->hasResume()) {
tcpClientP->deleteFile(fullFilePathP);
}
}
sendMessageToServer(response, clientSocketP);
}
FString FSocketClientTCPFileHandlerThread::readMessageFromServer(FSocket* socket){
int64 ticks1 = 0;
int64 ticks2 = 0;
int32 lastDataLengthFromHeader = 0;
FString message = FString();
TArray<uint8> byteDataArrayCache;
TArray<uint8> byteDataArray;
uint32 dataSize = 0;
TArray<FString> lines;
while (tcpClient->isRun() && socket != nullptr) {
ticks1 = FDateTime::Now().GetTicks();
socket->Wait(ESocketWaitConditions::WaitForRead, FTimespan::FromSeconds(waitForRead));
ticks2 = FDateTime::Now().GetTicks();
bool hasData = socket->HasPendingData(dataSize);
if (!hasData && ticks1 == ticks2) {
//if (showFTPLogs) {
// UE_LOG(LogTemp, Warning, TEXT("FTP Client: TCP connection broken."));
//}
//fireConnectionEvent(false, 0, "TCP connection broken.");
return "TCP connection broken.";
}
if (!hasData) {
return message;
}
if (hasData) {
TArray<uint8> dataFromSocket;
dataFromSocket.SetNumUninitialized(dataSize);
int32 BytesRead = 0;
if (socket->Recv(dataFromSocket.GetData(), dataFromSocket.Num(), BytesRead)) {
if (lastDataLengthFromHeader == 0 && dataFromSocket.Num() >= 5) {
tcpClient->readDataLength(dataFromSocket, lastDataLengthFromHeader);
if (dataFromSocket.Num() == 5) {
dataFromSocket.Empty();
continue;
}
byteDataArrayCache.Append(dataFromSocket.GetData() + 5, dataFromSocket.Num() - 5);
dataFromSocket.Empty();
}
else {
byteDataArrayCache.Append(dataFromSocket.GetData(), dataFromSocket.Num());
}
int32 maxLoops = 1000;//to prevent endless loop
while (byteDataArrayCache.Num() > 0 && byteDataArrayCache.Num() >= lastDataLengthFromHeader && maxLoops > 0) {
maxLoops--;
byteDataArray.Append(byteDataArrayCache.GetData(), lastDataLengthFromHeader);
byteDataArrayCache.RemoveAt(0, lastDataLengthFromHeader, true);
if (byteDataArrayCache.Num() == 0) {
lastDataLengthFromHeader = 0;
break;
}
if (byteDataArrayCache.Num() > 5) {
tcpClient->readDataLength(byteDataArrayCache, lastDataLengthFromHeader);
byteDataArrayCache.RemoveAt(0, 5, true);
}
}
byteDataArray.Add(0x00);// null-terminator
message = FString(UTF8_TO_TCHAR((char*)byteDataArray.GetData()));
byteDataArray.Empty();
if (message.IsEmpty() == false) {
message = tcpClient->decryptMessage(message);
}
return message;
}
}
}
if (message.IsEmpty() == false) {
message = tcpClient->decryptMessage(message);
}
return message;
}