增加多屏显示,视频播放
This commit is contained in:
+115
@@ -0,0 +1,115 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#include "DNSClientSocketClient.h"
|
||||
|
||||
UDNSClientSocketClient::UDNSClientSocketClient(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer) {
|
||||
}
|
||||
|
||||
|
||||
void UDNSClientSocketClient::resolveDomain(ISocketSubsystem* socketSubSystem, FString domainP, bool useDNSCache, FString dnsIP) {
|
||||
domain = domainP;
|
||||
resolving = true;
|
||||
if (useDNSCache) {
|
||||
if (dnsCache.Find(domain) != nullptr) {
|
||||
ip = *dnsCache.Find(domain);
|
||||
resolving = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
FIPv4Endpoint Endpoint;
|
||||
FString socketName;
|
||||
//FIPv4Endpoint::Parse("127.0.0.1:12345", Endpoint);
|
||||
//socket = FUdpSocketBuilder(*socketName).AsReusable().WithBroadcast().BoundToEndpoint(Endpoint);
|
||||
socket = FUdpSocketBuilder(*socketName).AsReusable().WithBroadcast();
|
||||
if (socket == nullptr || socket == NULL) {
|
||||
UE_LOG(LogTemp, Error, TEXT("UE4 could not init a UDP socket to resolve %s on %s."), *domain, *dnsIP);
|
||||
resolving = false;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
FTimespan ThreadWaitTime = FTimespan::FromMilliseconds(100);
|
||||
FUdpSocketReceiver* udpSocketReceiver = new FUdpSocketReceiver(socket, ThreadWaitTime, TEXT("UE4 DNSClient"));
|
||||
udpSocketReceiver->OnDataReceived().BindUObject(this, &UDNSClientSocketClient::UDPReceiver);
|
||||
udpSocketReceiver->Start();
|
||||
|
||||
TSharedRef<FInternetAddr> addr = socketSubSystem->CreateInternetAddr();
|
||||
bool bIsValid;
|
||||
addr->SetIp(*dnsIP, bIsValid);
|
||||
addr->SetPort(53);
|
||||
if (bIsValid) {
|
||||
TArray<unsigned char> dnsRequest;
|
||||
//id (ramdom choose)
|
||||
dnsRequest.Add(0x22);
|
||||
dnsRequest.Add(0x76);
|
||||
//head
|
||||
dnsRequest.Add(0x1);
|
||||
dnsRequest.Add(0x0);
|
||||
dnsRequest.Add(0x0);
|
||||
dnsRequest.Add(0x1);
|
||||
dnsRequest.Add(0x0);
|
||||
dnsRequest.Add(0x0);
|
||||
dnsRequest.Add(0x0);
|
||||
dnsRequest.Add(0x0);
|
||||
dnsRequest.Add(0x0);
|
||||
dnsRequest.Add(0x0);
|
||||
|
||||
//domain
|
||||
//split in domain parts than add the length as byte and the part as bytes
|
||||
TArray<FString> domainParts;
|
||||
domain.ParseIntoArray(domainParts, TEXT("."), true);
|
||||
for (int i = 0; i < domainParts.Num(); i++) {
|
||||
FTCHARToUTF8 Convert(*domainParts[i]);
|
||||
dnsRequest.Add(Convert.Length());
|
||||
dnsRequest.Append((uint8*)Convert.Get(), Convert.Length());
|
||||
}
|
||||
//foot
|
||||
dnsRequest.Add(0x0);
|
||||
dnsRequest.Add(0x0);
|
||||
dnsRequest.Add(0x1);
|
||||
dnsRequest.Add(0x0);
|
||||
dnsRequest.Add(0x1);
|
||||
int32 sent;
|
||||
socket->SendTo((uint8*)dnsRequest.GetData(), dnsRequest.Num(), sent, *addr);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void UDNSClientSocketClient::UDPReceiver(const FArrayReaderPtr& ArrayReaderPtr, const FIPv4Endpoint& EndPt) {
|
||||
|
||||
//TSharedPtr<FInternetAddr> peerAddr = EndPt.ToInternetAddr();
|
||||
//FString ip = peerAddr->ToString(false);
|
||||
//int32 port = peerAddr->GetPort();
|
||||
////UE_LOG(LogTemp, Error, TEXT("peerAddr:%s port:%i"), *peerAddr->ToString(false), peerAddr->GetPort());
|
||||
|
||||
|
||||
|
||||
TArray<uint8> byteArray;
|
||||
byteArray.Append(ArrayReaderPtr->GetData(), ArrayReaderPtr->Num());
|
||||
|
||||
FString ipAdress;
|
||||
if (byteArray.Num() > 10) {
|
||||
for (int32 i = (byteArray.Num() - 4); i < byteArray.Num(); i++) {
|
||||
uint32 ipTmp = byteArray.GetData()[i] << 0;
|
||||
ipAdress += FString::FromInt(ipTmp) + ".";
|
||||
}
|
||||
}
|
||||
|
||||
ipAdress.RemoveFromEnd(".");
|
||||
|
||||
//UE_LOG(LogTemp, Display, TEXT("DNS Resolved IP:%s"), *recvMessage);
|
||||
|
||||
ip = ipAdress;
|
||||
dnsCache.Add(domain, ip);
|
||||
|
||||
resolving = false;
|
||||
}
|
||||
|
||||
bool UDNSClientSocketClient::isResloving() {
|
||||
return resolving;
|
||||
}
|
||||
|
||||
FString UDNSClientSocketClient::getIP() {
|
||||
return ip;
|
||||
}
|
||||
+572
@@ -0,0 +1,572 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#include "FileFunctionsSocketClient.h"
|
||||
|
||||
UFileFunctionsSocketClient* UFileFunctionsSocketClient::fileFunctionsSocketClient;
|
||||
|
||||
UFileFunctionsSocketClient::UFileFunctionsSocketClient(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {
|
||||
fileFunctionsSocketClient = this;
|
||||
}
|
||||
|
||||
UFileFunctionsSocketClient* UFileFunctionsSocketClient::getFileFunctionsSocketClientTarget() {
|
||||
return fileFunctionsSocketClient;
|
||||
}
|
||||
|
||||
FString UFileFunctionsSocketClient::getCleanDirectory(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath) {
|
||||
if (directoryType == EFileFunctionsSocketClientDirectoryType::E_ad) {
|
||||
return FPaths::ConvertRelativePathToFull(filePath);
|
||||
}
|
||||
else {
|
||||
FString ProjectDir = FPaths::ProjectDir();
|
||||
return FPaths::ConvertRelativePathToFull(ProjectDir + filePath);
|
||||
}
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::writeBytesToFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, TArray<uint8> bytes, bool& success) {
|
||||
success = FFileHelper::SaveArrayToFile(bytes, *getCleanDirectory(directoryType, filePath));
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::addBytesToFileAndCloseIt(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, TArray<uint8> bytes, bool& success) {
|
||||
FArchive* writer = IFileManager::Get().CreateFileWriter(*getCleanDirectory(directoryType, filePath), EFileWrite::FILEWRITE_Append);
|
||||
if (!writer) {
|
||||
success = false;
|
||||
return;
|
||||
}
|
||||
writer->Seek(writer->TotalSize());
|
||||
writer->Serialize(bytes.GetData(), bytes.Num());
|
||||
writer->Close();
|
||||
delete writer;
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
//void UFileFunctionsSocketClient::splittFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, int32 parts, bool& success){
|
||||
// if (parts <= 0)
|
||||
// parts = 1;
|
||||
// FArchive* reader = IFileManager::Get().CreateFileReader(*getCleanDirectory(directoryType, filePath));
|
||||
// if (!reader) {
|
||||
// success = false;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// int64 splittAfterBytes = reader->TotalSize()/ ((int64)parts);
|
||||
// TArray<uint8> bytes;
|
||||
//
|
||||
// for (int32 i = 0; i < parts; i++){
|
||||
// bytes.AddUninitialized(splittAfterBytes);
|
||||
// reader->Serialize(bytes.GetData(), splittAfterBytes);
|
||||
// if (FFileHelper::SaveArrayToFile(bytes, *getCleanDirectory(directoryType, filePath)) == false) {
|
||||
// success = false;
|
||||
// return;
|
||||
// }
|
||||
// splittAfterBytes =
|
||||
// reader->Seek();
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
TArray<uint8> UFileFunctionsSocketClient::readBytesFromFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, bool& success) {
|
||||
TArray<uint8> result;
|
||||
success = FFileHelper::LoadFileToArray(result, *getCleanDirectory(directoryType, filePath));
|
||||
return result;
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::readStringFromFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, bool& success, FString& data) {
|
||||
data.Empty();
|
||||
success = FFileHelper::LoadFileToString(data, *getCleanDirectory(directoryType, filePath));
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::writeStringToFile(EFileFunctionsSocketClientDirectoryType directoryType, FString data, FString filePath, EFileFunctionsSocketClientEncodingOptions fileEncoding, bool& success) {
|
||||
success = FFileHelper::SaveStringToFile(data, *getCleanDirectory(directoryType, filePath), (FFileHelper::EEncodingOptions)fileEncoding);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void UFileFunctionsSocketClient::getMD5FromFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, bool& success, FString& MD5) {
|
||||
getMD5FromFileAbsolutePath(getCleanDirectory(directoryType, filePath), success, MD5);
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::getMD5FromFileAbsolutePath(FString filePath, bool& success, FString& MD5) {
|
||||
MD5.Empty();
|
||||
FArchive* reader = IFileManager::Get().CreateFileReader(*filePath);
|
||||
if (!reader) {
|
||||
success = false;
|
||||
return;
|
||||
}
|
||||
|
||||
TArray<uint8> byteArrayTmp;
|
||||
int64 totalSize = reader->TotalSize();
|
||||
int64 loadedBytes = 0;
|
||||
int64 leftUploadBytes = 1024;
|
||||
|
||||
|
||||
if (totalSize < leftUploadBytes)
|
||||
leftUploadBytes = totalSize;
|
||||
|
||||
|
||||
uint8 Digest[16];
|
||||
FMD5 Md5Gen;
|
||||
|
||||
while ((loadedBytes + leftUploadBytes) <= totalSize) {
|
||||
byteArrayTmp.Reset(leftUploadBytes);
|
||||
byteArrayTmp.AddUninitialized(leftUploadBytes);
|
||||
reader->Serialize(byteArrayTmp.GetData(), byteArrayTmp.Num());
|
||||
loadedBytes += leftUploadBytes;
|
||||
reader->Seek(loadedBytes);
|
||||
|
||||
Md5Gen.Update(byteArrayTmp.GetData(), byteArrayTmp.Num());
|
||||
}
|
||||
|
||||
leftUploadBytes = totalSize - loadedBytes;
|
||||
if (leftUploadBytes > 0) {
|
||||
byteArrayTmp.Reset(leftUploadBytes);
|
||||
byteArrayTmp.AddUninitialized(leftUploadBytes);
|
||||
reader->Serialize(byteArrayTmp.GetData(), byteArrayTmp.Num());
|
||||
loadedBytes += leftUploadBytes;
|
||||
Md5Gen.Update(byteArrayTmp.GetData(), byteArrayTmp.Num());
|
||||
}
|
||||
|
||||
if (reader != nullptr) {
|
||||
reader->Close();
|
||||
delete reader;
|
||||
}
|
||||
|
||||
if (totalSize != loadedBytes) {
|
||||
success = false;
|
||||
return;
|
||||
}
|
||||
|
||||
Md5Gen.Final(Digest);
|
||||
for (int32 i = 0; i < 16; i++) {
|
||||
MD5 += FString::Printf(TEXT("%02x"), Digest[i]);
|
||||
}
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::stringToBase64String(FString string, FString& base64String) {
|
||||
base64String.Empty();
|
||||
FTCHARToUTF8 Convert(*string);
|
||||
TArray<uint8> bytes;
|
||||
bytes.Append(((uint8*)((ANSICHAR*)Convert.Get())), Convert.Length());
|
||||
base64String = FBase64::Encode(bytes);
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::base64StringToString(FString& string, FString base64String) {
|
||||
string.Empty();
|
||||
TArray<uint8> bytes;
|
||||
if (FBase64::Decode(*base64String, bytes)) {
|
||||
bytes.Add(0x00);// null-terminator
|
||||
char* Data = (char*)bytes.GetData();
|
||||
string = FString(UTF8_TO_TCHAR(Data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void UFileFunctionsSocketClient::bytesToBase64String(TArray<uint8> bytes, FString& base64String) {
|
||||
base64String.Empty();
|
||||
base64String = FBase64::Encode(bytes);
|
||||
}
|
||||
|
||||
TArray<uint8> UFileFunctionsSocketClient::base64StringToBytes(FString base64String, bool& success) {
|
||||
TArray<uint8> fileData;
|
||||
if (base64String.Len() % 2 != 0 || base64String.Len() < 4) {
|
||||
success = false;
|
||||
return fileData;
|
||||
}
|
||||
success = FBase64::Decode(*base64String, fileData);
|
||||
return fileData;
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::fileToBase64String(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, bool& success, FString& base64String, FString& fileName) {
|
||||
base64String.Empty();
|
||||
fileName.Empty();
|
||||
TArray<uint8> fileData;
|
||||
if (!FFileHelper::LoadFileToArray(fileData, *getCleanDirectory(directoryType, filePath))) {
|
||||
success = false;
|
||||
return;
|
||||
}
|
||||
base64String = FBase64::Encode(fileData);
|
||||
success = true;
|
||||
}
|
||||
|
||||
bool UFileFunctionsSocketClient::fileExists(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath) {
|
||||
return FPaths::FileExists(*getCleanDirectory(directoryType, filePath));
|
||||
}
|
||||
|
||||
bool UFileFunctionsSocketClient::fileExistsAbsolutePath(FString filePath) {
|
||||
return FPaths::FileExists(*filePath);
|
||||
}
|
||||
|
||||
bool UFileFunctionsSocketClient::directoryExists(EFileFunctionsSocketClientDirectoryType directoryType, FString path) {
|
||||
return FPaths::DirectoryExists(*getCleanDirectory(directoryType, path));
|
||||
}
|
||||
|
||||
int64 UFileFunctionsSocketClient::fileSize(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().FileSize(*getCleanDirectory(directoryType, filePath));
|
||||
}
|
||||
|
||||
int64 UFileFunctionsSocketClient::fileSizeAbsolutePath(FString filePath) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().FileSize(*filePath);
|
||||
}
|
||||
|
||||
bool UFileFunctionsSocketClient::deleteFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*getCleanDirectory(directoryType, filePath));
|
||||
}
|
||||
|
||||
bool UFileFunctionsSocketClient::deleteFileAbsolutePath(FString filePath) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*filePath);
|
||||
}
|
||||
|
||||
|
||||
bool UFileFunctionsSocketClient::deleteDirectory(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().DeleteDirectory(*getCleanDirectory(directoryType, filePath));
|
||||
}
|
||||
|
||||
bool UFileFunctionsSocketClient::isReadOnly(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().IsReadOnly(*getCleanDirectory(directoryType, filePath));
|
||||
}
|
||||
|
||||
bool UFileFunctionsSocketClient::moveFile(EFileFunctionsSocketClientDirectoryType directoryTypeTo, FString filePathTo, EFileFunctionsSocketClientDirectoryType directoryTypeFrom, FString filePathFrom) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().MoveFile(*getCleanDirectory(directoryTypeTo, filePathTo), *getCleanDirectory(directoryTypeFrom, filePathFrom));
|
||||
}
|
||||
|
||||
bool UFileFunctionsSocketClient::setReadOnly(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, bool bNewReadOnlyValue) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().SetReadOnly(*getCleanDirectory(directoryType, filePath), bNewReadOnlyValue);
|
||||
}
|
||||
|
||||
FDateTime UFileFunctionsSocketClient::getTimeStamp(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().GetTimeStamp(*getCleanDirectory(directoryType, filePath));
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::setTimeStamp(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, FDateTime DateTime) {
|
||||
FPlatformFileManager::Get().GetPlatformFile().SetTimeStamp(*getCleanDirectory(directoryType, filePath), DateTime);
|
||||
}
|
||||
|
||||
FDateTime UFileFunctionsSocketClient::getAccessTimeStamp(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().GetAccessTimeStamp(*getCleanDirectory(directoryType, filePath));
|
||||
}
|
||||
|
||||
FString UFileFunctionsSocketClient::getFilenameOnDisk(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().GetFilenameOnDisk(*getCleanDirectory(directoryType, filePath));
|
||||
}
|
||||
|
||||
bool UFileFunctionsSocketClient::createDirectory(EFileFunctionsSocketClientDirectoryType directoryType, FString path) {
|
||||
return FPlatformFileManager::Get().GetPlatformFile().CreateDirectory(*getCleanDirectory(directoryType, path));
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::getAllFilesFromDirectory(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, int32& count, TArray<FString>& files, TArray<FString>& filePaths, FString fileType) {
|
||||
if (filePath.Len() < 1) {
|
||||
return;
|
||||
}
|
||||
files.Empty();
|
||||
filePaths.Empty();
|
||||
|
||||
FString dir = getCleanDirectory(directoryType, filePath);
|
||||
FPaths::NormalizeDirectoryName(filePath);
|
||||
|
||||
if (!FPaths::DirectoryExists(dir)) {
|
||||
return;
|
||||
}
|
||||
IFileManager& FileManager = IFileManager::Get();
|
||||
|
||||
dir += "/" + fileType;
|
||||
|
||||
FileManager.FindFiles(files, *dir, true, false);
|
||||
|
||||
|
||||
filePath += "/";
|
||||
for (int32 i = 0; i < files.Num(); i++) {
|
||||
filePaths.Add((filePath + files[i]));
|
||||
//UE_LOG(LogTemp, Display, TEXT("->%s"), *files[i]);
|
||||
}
|
||||
count = files.Num();
|
||||
}
|
||||
|
||||
FFileFunctionsSocketClientOpenFile UFileFunctionsSocketClient::openFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath){
|
||||
|
||||
FArchive* writer = IFileManager::Get().CreateFileWriter(*getCleanDirectory(directoryType, filePath), EFileWrite::FILEWRITE_Append);
|
||||
FFileFunctionsSocketClientOpenFile file;
|
||||
file.writer = writer;
|
||||
return file;
|
||||
}
|
||||
|
||||
int64 UFileFunctionsSocketClient::addBytesToFile(FFileFunctionsSocketClientOpenFile openFile, TArray<uint8> bytes){
|
||||
//UE_LOG(LogTemp, Warning, TEXT("xxxxx WRITE: %i"), bytes.Num());
|
||||
if (openFile.writer != nullptr) {
|
||||
openFile.writer->Seek(openFile.writer->TotalSize());
|
||||
openFile.writer->Serialize(bytes.GetData(), bytes.Num());
|
||||
//openFile.writer->Flush();
|
||||
return openFile.writer->TotalSize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::closeFile(FFileFunctionsSocketClientOpenFile openFile){
|
||||
if (openFile.writer != nullptr) {
|
||||
openFile.writer->Close();
|
||||
openFile.writer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool UFileFunctionsSocketClient::encryptFileWithAES(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, FString newFileName, FString key, bool writeEncryptedFileSizeToFile){
|
||||
|
||||
if (filePath.IsEmpty() || newFileName.IsEmpty() || key.Len() != 32) {
|
||||
UE_LOG(LogTemp, Error, TEXT("encryptFileWithAES: FilePath or newFileName empty or wrong key length. The key must consist of 32 ANSI compatible characters."));
|
||||
return false;
|
||||
}
|
||||
|
||||
FString dir = getCleanDirectory(directoryType, filePath);
|
||||
FString fileName = FPaths::GetCleanFilename(dir);
|
||||
int64 fileSize = FPlatformFileManager::Get().GetPlatformFile().FileSize(*dir);
|
||||
|
||||
TArray64<uint8> data;
|
||||
if (!FFileHelper::LoadFileToArray(data, *dir)) {
|
||||
UE_LOG(LogTemp, Error, TEXT("encryptFileWithAES: File could not be loaded: %s"),*dir);
|
||||
return false;
|
||||
}
|
||||
|
||||
const int64 encryptedFileSize = Align(data.Num(), FAES::AESBlockSize);
|
||||
|
||||
if (data.Num() < encryptedFileSize) {
|
||||
data.AddUninitialized(encryptedFileSize - data.Num());
|
||||
}
|
||||
|
||||
FAES::EncryptData(data.GetData(), encryptedFileSize, TCHAR_TO_ANSI(*key));
|
||||
|
||||
dir = dir.Replace(*fileName, *newFileName);
|
||||
if (FPaths::FileExists(*dir)) {
|
||||
FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*dir);
|
||||
}
|
||||
|
||||
FArchive* writer = IFileManager::Get().CreateFileWriter(*dir, EFileWrite::FILEWRITE_Append);
|
||||
if (!writer) {
|
||||
UE_LOG(LogTemp, Error, TEXT("encryptFileWithAES: File could not be saved: %s"), *dir);
|
||||
data.Empty();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (writeEncryptedFileSizeToFile) {
|
||||
TArray<uint8> byteArray;
|
||||
union {
|
||||
int64 tmpVal;
|
||||
uint8 tmpArray[8];
|
||||
} u;
|
||||
u.tmpVal = fileSize;
|
||||
byteArray.AddZeroed(8);
|
||||
|
||||
FMemory::Memcpy(byteArray.GetData(), u.tmpArray, 8);
|
||||
writer->Serialize(byteArray.GetData(), byteArray.Num());
|
||||
byteArray.Empty();
|
||||
}
|
||||
|
||||
writer->Serialize(data.GetData(), data.Num());
|
||||
writer->Close();
|
||||
delete writer;
|
||||
|
||||
data.Empty();
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool UFileFunctionsSocketClient::decryptFileWithAES(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, FString newFileName, FString key,
|
||||
bool hasEncryptedFileSizeInFile, int64 originalFileLength){
|
||||
|
||||
if (filePath.IsEmpty() || newFileName.IsEmpty() || key.Len() != 32) {
|
||||
UE_LOG(LogTemp, Error, TEXT("decryptFileWithAES: FilePath or newFileName empty or wrong key length. The key must consist of 32 ANSI compatible characters."));
|
||||
return false;
|
||||
}
|
||||
|
||||
FString dir = getCleanDirectory(directoryType, filePath);
|
||||
FString fileName = FPaths::GetCleanFilename(dir);
|
||||
int64 fileSize = FPlatformFileManager::Get().GetPlatformFile().FileSize(*dir);
|
||||
|
||||
FArchive* reader = IFileManager::Get().CreateFileReader(*dir);
|
||||
if (!reader) {
|
||||
UE_LOG(LogTemp, Error, TEXT("decryptFileWithAES: File could not be loaded: %s"), *dir);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasEncryptedFileSizeInFile) {
|
||||
TArray<uint8> bytes;
|
||||
bytes.AddZeroed(8);
|
||||
reader->Serialize(bytes.GetData(), bytes.Num());
|
||||
FMemory::Memcpy(&originalFileLength, bytes.GetData(), 8);
|
||||
bytes.Empty();
|
||||
fileSize = fileSize-8;
|
||||
}
|
||||
|
||||
if (fileSize < originalFileLength) {
|
||||
originalFileLength = fileSize;
|
||||
UE_LOG(LogTemp, Warning, TEXT("decryptFileWithAES: The encrypted file size is smaller than the original file size. File may be corrupted: %s"), *dir);
|
||||
return false;
|
||||
}
|
||||
|
||||
TArray64<uint8> data;
|
||||
data.AddUninitialized(fileSize);
|
||||
reader->Serialize(data.GetData(), data.Num());
|
||||
reader->Close();
|
||||
delete reader;
|
||||
|
||||
|
||||
const int64 encryptedFileSize = Align(data.Num(), FAES::AESBlockSize);
|
||||
if (data.Num() < encryptedFileSize) {
|
||||
UE_LOG(LogTemp, Error, TEXT("decryptFileWithAES: Wrong data length. File could not be decrypted: %s"),*dir);
|
||||
return false;
|
||||
}
|
||||
|
||||
FAES::DecryptData(data.GetData(), encryptedFileSize, TCHAR_TO_ANSI(*key));
|
||||
|
||||
dir = dir.Replace(*fileName, *newFileName);
|
||||
if (FPaths::FileExists(*dir)) {
|
||||
FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*dir);
|
||||
}
|
||||
|
||||
FArchive* writer = IFileManager::Get().CreateFileWriter(*dir, EFileWrite::FILEWRITE_Append);
|
||||
if (!writer) {
|
||||
UE_LOG(LogTemp, Error, TEXT("encryptFileWithAES: File could not be saved: %s"), *dir);
|
||||
data.Empty();
|
||||
return false;
|
||||
}
|
||||
writer->Serialize(data.GetData(), originalFileLength);
|
||||
writer->Close();
|
||||
delete writer;
|
||||
|
||||
data.Empty();
|
||||
return true;
|
||||
}
|
||||
|
||||
FString UFileFunctionsSocketClient::encryptMessageWithAES(FString message, FString key) {
|
||||
|
||||
if (message.IsEmpty() || key.Len() != 32) {
|
||||
UE_LOG(LogTemp, Error, TEXT("encryptMessageWithAES:Message empty or wrong key length. The key must consist of 32 ANSI compatible characters."));
|
||||
return FString();
|
||||
}
|
||||
|
||||
TArray<uint8> data = FStringToByteArray(message);
|
||||
data.Add(0x00);// null-terminator
|
||||
const int64 encryptedFileSize = Align(data.Num(), FAES::AESBlockSize);
|
||||
|
||||
if (data.Num() < encryptedFileSize){
|
||||
data.AddUninitialized(encryptedFileSize-data.Num());
|
||||
}
|
||||
|
||||
FAES::EncryptData(data.GetData(), encryptedFileSize, TCHAR_TO_ANSI(*key));
|
||||
|
||||
FString encryptedBase64String = FString();
|
||||
bytesToBase64String(data, encryptedBase64String);
|
||||
|
||||
data.Empty();
|
||||
|
||||
return encryptedBase64String;
|
||||
}
|
||||
|
||||
FString UFileFunctionsSocketClient::decryptMessageWithAES(FString message, FString key) {
|
||||
if (message.IsEmpty() || key.Len() != 32) {
|
||||
UE_LOG(LogTemp, Error, TEXT("decryptMessageFromAES: Message empty or wrong key length. The key must consist of 32 ANSI compatible characters."));
|
||||
return FString();
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
TArray<uint8> data = base64StringToBytes(message, success);
|
||||
|
||||
|
||||
const int64 encryptedFileSize = Align(data.Num(), FAES::AESBlockSize);
|
||||
if (data.Num() < encryptedFileSize) {
|
||||
UE_LOG(LogTemp, Error, TEXT("decryptMessageFromAES: Wrong string length. Message could not be decrypted."));
|
||||
return FString();
|
||||
}
|
||||
|
||||
FAES::DecryptData(data.GetData(), encryptedFileSize, TCHAR_TO_ANSI(*key));
|
||||
|
||||
FString s = FString(UTF8_TO_TCHAR((char*)data.GetData()));
|
||||
|
||||
data.Empty();
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
TArray<uint8> UFileFunctionsSocketClient::FStringToByteArray(FString s) {
|
||||
FTCHARToUTF8 Convert(*s);
|
||||
TArray<uint8> data;
|
||||
data.Append((uint8*)Convert.Get(), Convert.Length());
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
FString UFileFunctionsSocketClient::int64ToString(int64 Num) {
|
||||
FString str = FString();
|
||||
const TCHAR* DigitToChar = TEXT("9876543210123456789");
|
||||
constexpr int64 ZeroDigitIndex = 9;
|
||||
bool bIsNumberNegative = Num < 0;
|
||||
const int64 TempBufferSize = 32; // 32 is big enough
|
||||
TCHAR TempNum[TempBufferSize];
|
||||
int64 TempAt = TempBufferSize; // fill the temp string from the top down.
|
||||
|
||||
// Convert to string assuming base ten.
|
||||
do
|
||||
{
|
||||
TempNum[--TempAt] = DigitToChar[ZeroDigitIndex + (Num % 10)];
|
||||
Num /= 10;
|
||||
} while (Num);
|
||||
|
||||
if (bIsNumberNegative)
|
||||
{
|
||||
TempNum[--TempAt] = TEXT('-');
|
||||
}
|
||||
|
||||
const TCHAR* CharPtr = TempNum + TempAt;
|
||||
const int64 NumChars = TempBufferSize - TempAt;
|
||||
str.Append(CharPtr, NumChars);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void UFileFunctionsSocketClient::readBytesFromFileInPartsAsync(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, int32 bufferSize, float delayBetweenReadsInSeconds) {
|
||||
UFileFunctionsSocketClient::getFileFunctionsSocketClientTarget()->readBytesFromFileInPartsAsyncInternal(directoryType, filePath, bufferSize, delayBetweenReadsInSeconds);
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::readBytesFromFileInPartsAsyncInternal(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, int32 bufferSize, float delayBetweenReadsInSeconds) {
|
||||
|
||||
FString dir = UFileFunctionsSocketClient::getCleanDirectory(directoryType, filePath);
|
||||
|
||||
if (readFileInPartsThreads.Find(*dir) != nullptr) {
|
||||
UE_LOG(LogTemp, Warning, TEXT("ReadBytesFromFileInPartsAsync: %s is being read already. Operation canceled."), *dir);
|
||||
return;
|
||||
}
|
||||
|
||||
FReadFileInPartsSocketClientThread* readThread = new FReadFileInPartsSocketClientThread(dir, bufferSize, delayBetweenReadsInSeconds);
|
||||
readFileInPartsThreads.Add(dir, readThread);
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::cancelReadBytesFromFileInParts(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath) {
|
||||
UFileFunctionsSocketClient::getFileFunctionsSocketClientTarget()->cancelReadBytesFromFileInPartsInternal(directoryType, filePath);
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::cancelReadBytesFromFileInPartsInternal(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath) {
|
||||
FString dir = UFileFunctionsSocketClient::getCleanDirectory(directoryType, filePath);
|
||||
|
||||
if (readFileInPartsThreads.Find(*dir) != nullptr) {
|
||||
(*readFileInPartsThreads.Find(*dir))->stopThread();
|
||||
}
|
||||
}
|
||||
|
||||
void UFileFunctionsSocketClient::cleanReadBytesFromFileInParts(FString cleanDir) {
|
||||
if (readFileInPartsThreads.Find(*cleanDir) != nullptr) {
|
||||
readFileInPartsThreads.Remove(*cleanDir);
|
||||
}
|
||||
}
|
||||
|
||||
//void UFileFunctionsSocketClient::changeDelayInBytesFromFileInParts(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, float delayBetweenReadsInSeconds) {
|
||||
// FString dir = UFileFunctionsSocketClient::getCleanDirectory(directoryType, filePath);
|
||||
//
|
||||
// if (readFileInPartsThreads.Find(*dir) != nullptr) {
|
||||
// (*readFileInPartsThreads.Find(*dir))->setDelayBetweenReadsInSeconds(delayBetweenReadsInSeconds);
|
||||
// }
|
||||
//}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
#include "SocketClient.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "FSocketClientModule"
|
||||
|
||||
bool FSocketClientModule::isShuttingDown;
|
||||
|
||||
void FSocketClientModule::StartupModule()
|
||||
{
|
||||
// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module
|
||||
|
||||
}
|
||||
|
||||
void FSocketClientModule::ShutdownModule()
|
||||
{
|
||||
// This function may be called during shutdown to clean up your module. For modules that support dynamic reloading,
|
||||
// we call this function before unloading the module.
|
||||
isShuttingDown = true;
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
||||
IMPLEMENT_MODULE(FSocketClientModule, SocketClient)
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
// Copyright 2022 David Romanski(Socke). All Rights Reserved.
|
||||
|
||||
#include "SocketClientAsyncNodes.h"
|
||||
|
||||
|
||||
/*--- TCP -------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
UTCPConnectAsyncNode* UTCPConnectAsyncNode::socketClientTCPConnectionAsyncNode(FString domainOrI, ESocketClientIPType ipType, int32 port,
|
||||
EReceiveFilterClient receiveFilters, ESocketClientTCPSeparator messageWrapping, FString optionalCustomConnectionID, bool disableNaglesAlgorithm) {
|
||||
|
||||
UTCPConnectAsyncNode* instance = NewObject<UTCPConnectAsyncNode>();
|
||||
|
||||
instance->domainOrIP = domainOrI;
|
||||
instance->ipType = ipType;
|
||||
instance->port = port;
|
||||
instance->receiveFilters = receiveFilters;
|
||||
instance->messageWrapping = messageWrapping;
|
||||
instance->optionalCustomConnectionID = optionalCustomConnectionID;
|
||||
instance->disableNaglesAlgorithm = disableNaglesAlgorithm;
|
||||
|
||||
instance->AddToRoot();
|
||||
|
||||
//The node is only visible in Blueprints if the function is declared in a UBlueprintAsyncActionBase class.
|
||||
//Therefore an instance of itself is created here.
|
||||
return instance;
|
||||
}
|
||||
|
||||
void UTCPConnectAsyncNode::Activate() {
|
||||
USocketClientBPLibrary::getSocketClientTarget()->connectSocketClientTCPNonStatic(domainOrIP, ipType, port, receiveFilters,
|
||||
messageWrapping,optionalCustomConnectionID, connectionID, this, disableNaglesAlgorithm);
|
||||
}
|
||||
|
||||
void UTCPConnectAsyncNode::triggerConnectionEvent(bool success, FString clientConnectionID, FString serverMessage){
|
||||
if (success) {
|
||||
OnConnect.Broadcast(serverMessage, clientConnectionID, "", TArray<uint8>());
|
||||
}
|
||||
else {
|
||||
OnDisconnect.Broadcast(serverMessage, clientConnectionID, "", TArray<uint8>());
|
||||
}
|
||||
}
|
||||
|
||||
void UTCPConnectAsyncNode::triggerMessageEvent(TArray<uint8> byteDataArray, FString clientConnectionID, FString serverMessage){
|
||||
OnServerMessage.Broadcast("",clientConnectionID,serverMessage,byteDataArray);
|
||||
}
|
||||
|
||||
|
||||
/*--- UDP -------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
UUDPInitAsyncNode* UUDPInitAsyncNode::socketClientInitUDPReceiverAsyncNode(FString domainOrIP,ESocketClientIPType ipType, int32 port,
|
||||
EReceiveFilterClient receiveFilter, int32 maxPacketSize) {
|
||||
|
||||
UUDPInitAsyncNode* instance = NewObject<UUDPInitAsyncNode>();
|
||||
|
||||
instance->domainOrIP = domainOrIP;
|
||||
instance->ipType = ipType;
|
||||
instance->port = port;
|
||||
instance->receiveFilter = receiveFilter;
|
||||
instance->maxPacketSize = maxPacketSize;
|
||||
instance->AddToRoot();
|
||||
|
||||
//The node is only visible in Blueprints if the function is declared in a UBlueprintAsyncActionBase class.
|
||||
//Therefore an instance of itself is created here.
|
||||
return instance;
|
||||
}
|
||||
|
||||
void UUDPInitAsyncNode::Activate() {
|
||||
USocketClientBPLibrary::getSocketClientTarget()->socketClientInitUDPReceiverNonStatic(connectionID, this,domainOrIP, ipType, port,
|
||||
receiveFilter, maxPacketSize);
|
||||
}
|
||||
|
||||
void UUDPInitAsyncNode::triggerInitEvent(bool success, FString clientConnectionID, FString serverMessage) {
|
||||
if (success) {
|
||||
OnSuccess.Broadcast(serverMessage, clientConnectionID,"",0, "", TArray<uint8>());
|
||||
}
|
||||
else {
|
||||
OnFail.Broadcast(serverMessage, clientConnectionID, "",0,"", TArray<uint8>());
|
||||
}
|
||||
}
|
||||
|
||||
void UUDPInitAsyncNode::triggerMessageEvent(TArray<uint8> byteDataArray, FString clientConnectionID, FString serverMessage, FString peerIP, int32 peerPort) {
|
||||
OnServerMessage.Broadcast("", clientConnectionID,peerIP, peerPort, serverMessage, byteDataArray);
|
||||
}
|
||||
+734
@@ -0,0 +1,734 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#include "SocketClientBPLibrary.h"
|
||||
#include "SocketClient.h"
|
||||
|
||||
USocketClientBPLibrary* USocketClientBPLibrary::socketClientBPLibrary;
|
||||
|
||||
USocketClientBPLibrary::USocketClientBPLibrary(const FObjectInitializer& ObjectInitializer)
|
||||
: Super(ObjectInitializer) {
|
||||
|
||||
socketClientBPLibrary = this;
|
||||
|
||||
if (socketClientCleanerThread == nullptr)
|
||||
socketClientCleanerThread = new FSocketClientCleanerThread();
|
||||
}
|
||||
|
||||
/*Delegate functions*/
|
||||
void USocketClientBPLibrary::socketClientTCPConnectionEventDelegate(const bool success, const FString message, const FString clientConnectionIDP) {}
|
||||
void USocketClientBPLibrary::receiveTCPMessageEventDelegate(const FString message, const TArray<uint8>& byteArray, const FString clientConnectionIDP) {}
|
||||
void USocketClientBPLibrary::socketClientUDPConnectionEventDelegate(const bool success, const FString message, const FString clientConnectionID) {}
|
||||
void USocketClientBPLibrary::receiveUDPMessageEventDelegate(const FString message, const TArray<uint8>& byteArray, const FString IP, const int32 port,const FString clientConnectionID) {}
|
||||
void USocketClientBPLibrary::transferFileOverTCPProgressEventDelegate(const FString clientConnectionID, const FString filePath, const float percent, const float mbit, const int64 bytesSend, const int64 fileSize){}
|
||||
void USocketClientBPLibrary::fileTransferOverTCPInfoEventDelegate(const FString message, const FString clientConnectionID, const FString filePath, const bool success){}
|
||||
void USocketClientBPLibrary::readBytesFromFileInPartsEventDelegate(const int64 fileSize, const int64 position, const bool end, const TArray<uint8>& byteArray){}
|
||||
|
||||
|
||||
USocketClientBPLibrary::~USocketClientBPLibrary() {
|
||||
|
||||
}
|
||||
|
||||
USocketClientBPLibrary* USocketClientBPLibrary::getSocketClientTarget() {
|
||||
return socketClientBPLibrary;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FString USocketClientBPLibrary::getLocalIP() {
|
||||
bool canBind = false;
|
||||
TSharedRef<FInternetAddr> localIp = USocketClientBPLibrary::getSocketClientTarget()->getSocketSubSystem()->GetLocalHostAddr(*GLog, canBind);
|
||||
|
||||
if (localIp->IsValid()) {
|
||||
FString localIP = localIp->ToString(false);
|
||||
if (localIP.Equals("127.0.0.1")) {
|
||||
UE_LOG(LogTemp, Error, TEXT("Could not detect the local IP."));
|
||||
return "0.0.0.0";
|
||||
}
|
||||
return localIp->ToString(false);
|
||||
}
|
||||
else {
|
||||
UE_LOG(LogTemp, Error, TEXT("Could not detect the local IP."));
|
||||
}
|
||||
return "0.0.0.0";
|
||||
}
|
||||
|
||||
|
||||
void USocketClientBPLibrary::connectSocketClientTCP(FString domainOrIP, ESocketClientIPType ipType, int32 port, EReceiveFilterClient receiveFilters,
|
||||
ESocketClientTCPSeparator messageSeparator, FString optionalCustomConnectionID, FString& connectionID, bool disableNaglesAlgorithm){
|
||||
USocketClientBPLibrary::getSocketClientTarget()->connectSocketClientTCPNonStatic(domainOrIP, ipType, port, receiveFilters,
|
||||
messageSeparator,optionalCustomConnectionID, connectionID, nullptr,disableNaglesAlgorithm);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::connectSocketClientTCPNonStatic(FString domain, ESocketClientIPType ipType, int32 port, EReceiveFilterClient receiveFilter,
|
||||
ESocketClientTCPSeparator messageSeparator, FString optionalCustomConnectionID, FString& connectionID, UTCPConnectAsyncNode* tcpConnectAsyncNode, bool noPacketDelay) {
|
||||
|
||||
USocketClientTCPClient* tcpClient = NewObject<USocketClientTCPClient>(USocketClientTCPClient::StaticClass());
|
||||
if (optionalCustomConnectionID.IsEmpty()) {
|
||||
connectionID = FGuid::NewGuid().ToString();
|
||||
}
|
||||
else {
|
||||
connectionID = optionalCustomConnectionID;
|
||||
if (tcpClients.Find(connectionID) != nullptr) {
|
||||
FString serverMessage = "An existing connection with this ID was found. Connection establishment was aborted";
|
||||
UE_LOG(LogTemp, Warning, TEXT("An existing connection with this ID was found. Connection establishment was aborted. %s"), *connectionID);
|
||||
onsocketClientTCPConnectionEventDelegate.Broadcast(false, serverMessage, connectionID);
|
||||
|
||||
tcpClient->onsocketClientTCPConnectionEventDelegate.Broadcast(false, serverMessage, connectionID);
|
||||
if (tcpConnectAsyncNode != nullptr) {
|
||||
tcpConnectAsyncNode->triggerConnectionEvent(false, connectionID, serverMessage);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tcpClients.Add(connectionID, tcpClient);
|
||||
tcpClient->connect(this, domain, ipType, port, receiveFilter, messageSeparator, connectionID,tcpConnectAsyncNode, noPacketDelay, false);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::socketClientSendTCP(FString connectionID, FString message, TArray<uint8> byteArray, bool addLineBreak){
|
||||
USocketClientBPLibrary::getSocketClientTarget()->socketClientSendTCPNonStatic(connectionID, message, byteArray, addLineBreak);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::socketClientSendTCPNonStatic(FString connectionID,FString message, TArray<uint8> byteArray, bool addLineBreak) {
|
||||
|
||||
if (connectionID.IsEmpty() || tcpClients.Find(connectionID) == nullptr) {
|
||||
//don't send to many error messages. one second = 10000000 ticks
|
||||
if (((FDateTime::Now().GetTicks()) - lastErrorMessageTime) >= 10000000) {
|
||||
UE_LOG(LogTemp, Error, TEXT("Connection not found (socketClientSendTCPMessage). %s"), *connectionID);
|
||||
lastErrorMessageTime = FDateTime::Now().GetTicks();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.Len() > 0) {
|
||||
if (addLineBreak) {
|
||||
message.Append("\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
USocketClientTCPClient* tcpClient = *tcpClients.Find(connectionID);
|
||||
tcpClient->sendMessage(message, byteArray);
|
||||
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::socketClientSendFileOverTCP(FString& connectionID, FString domainOrIP, ESocketClientIPType ipType, int32 port,
|
||||
EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, FString token, FString Aes256bitKey){
|
||||
|
||||
USocketClientBPLibrary::getSocketClientTarget()->socketClientSendFileOverTCPNonStatic(connectionID, domainOrIP, ipType,
|
||||
port, directoryType, filePath, token, Aes256bitKey);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::socketClientSendFileOverTCPNonStatic(FString& connectionID, FString domainOrIP, ESocketClientIPType ipType,
|
||||
int32 port, EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, FString token, FString Aes256bitKey){
|
||||
|
||||
USocketClientTCPClient* tcpClient = NewObject<USocketClientTCPClient>(USocketClientTCPClient::StaticClass());
|
||||
connectionID = FGuid::NewGuid().ToString();
|
||||
tcpClients.Add(connectionID, tcpClient);
|
||||
tcpClient->sendFile(this, connectionID, domainOrIP, ipType, port, directoryType, filePath, token, Aes256bitKey);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::socketClientRequestFileOverTCP(FString& connectionID, FString domainOrIP, ESocketClientIPType ipType, int32 port,
|
||||
EFileFunctionsSocketClientDirectoryType directoryType, FString downloadDirectory, bool resume, FString token, FString Aes256bitKey){
|
||||
|
||||
USocketClientBPLibrary::getSocketClientTarget()->socketClientRequestFileOverTCPNonStatic(connectionID, domainOrIP, ipType, port,
|
||||
directoryType, downloadDirectory, resume, token, Aes256bitKey);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::socketClientRequestFileOverTCPNonStatic(FString& connectionID, FString domainOrIP, ESocketClientIPType ipType, int32 port,
|
||||
EFileFunctionsSocketClientDirectoryType directoryType, FString downloadDirectory, bool resume, FString token, FString Aes256bitKey) {
|
||||
USocketClientTCPClient* tcpClient = NewObject<USocketClientTCPClient>(USocketClientTCPClient::StaticClass());
|
||||
connectionID = FGuid::NewGuid().ToString();
|
||||
tcpClients.Add(connectionID, tcpClient);
|
||||
tcpClient->requestFile(this, connectionID, domainOrIP, ipType, port, directoryType, downloadDirectory, resume,token, Aes256bitKey);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void USocketClientBPLibrary::closeSocketClientConnectionTCP(FString connectionID){
|
||||
USocketClientBPLibrary::getSocketClientTarget()->closeSocketClientConnectionTCPNonStatic(connectionID);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::closeSocketClientConnectionTCPNonStatic(FString connectionID){
|
||||
if (connectionID.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (tcpClients.Find(connectionID) == nullptr) {
|
||||
UE_LOG(LogTemp, Error, TEXT("Connection not found (closeSocketClientTCPConnection). %s"), *connectionID);
|
||||
return;
|
||||
}
|
||||
|
||||
USocketClientTCPClient* tcpClient = *tcpClients.Find(connectionID);
|
||||
if (tcpClient != nullptr) {
|
||||
if (tcpClient->isRun()) {
|
||||
tcpClient->closeConnection();
|
||||
}
|
||||
}
|
||||
tcpClients.Remove(connectionID);
|
||||
tcpClient = nullptr;
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::closeAllSocketClientConnectionsTCP(){
|
||||
USocketClientBPLibrary::getSocketClientTarget()->closeAllSocketClientConnectionsTCPNonStatic();
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::closeAllSocketClientConnectionsTCPNonStatic(){
|
||||
|
||||
TArray<FString> tmpArray;
|
||||
tcpClients.GetKeys(tmpArray);
|
||||
|
||||
for (int32 i = 0; i < tmpArray.Num(); i++){
|
||||
closeSocketClientConnectionTCPNonStatic(tmpArray[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::getTCPConnectionByConnectionID(FString connectionID, bool& found, USocketClientTCPClient*& connection){
|
||||
USocketClientBPLibrary::getSocketClientTarget()->getTCPConnectionByConnectionIDNonStatic(connectionID, found, connection);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::getTCPConnectionByConnectionIDNonStatic(FString connectionID, bool& found, USocketClientTCPClient* &connection){
|
||||
if (connectionID.IsEmpty() || tcpClients.Find(connectionID) == nullptr) {
|
||||
found = false;
|
||||
connection = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
found = true;
|
||||
connection = *tcpClients.Find(connectionID);
|
||||
}
|
||||
|
||||
bool USocketClientBPLibrary::isTCPConnected(FString connectionID){
|
||||
return USocketClientBPLibrary::getSocketClientTarget()->isTCPConnectedNonStatic(connectionID);
|
||||
}
|
||||
|
||||
bool USocketClientBPLibrary::isTCPConnectedNonStatic(FString connectionID){
|
||||
if (connectionID.IsEmpty() || tcpClients.Find(connectionID) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
USocketClientTCPClient* tcpClient = *tcpClients.Find(connectionID);
|
||||
if (tcpClient->isRun() && tcpClient->isConnected()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void USocketClientBPLibrary::socketClientInitUDPReceiver(FString& connectionID, FString domainOrIP, ESocketClientIPType ipType, int32 port, EReceiveFilterClient receiveFilter, int32 maxPacketSize){
|
||||
USocketClientBPLibrary::getSocketClientTarget()->socketClientInitUDPReceiverNonStatic(connectionID,nullptr, domainOrIP, ipType, port, receiveFilter, maxPacketSize);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::socketClientInitUDPReceiverNonStatic(FString& connectionID, UUDPInitAsyncNode* udpInitAsyncNode, FString domain,
|
||||
ESocketClientIPType ipType, int32 port, EReceiveFilterClient receiveFilter, int32 maxPacketSize) {
|
||||
|
||||
FString key = domain + FString::FromInt(port);
|
||||
if (udpClients.Find(key) != nullptr) {
|
||||
USocketClientUDP* udpClient = *udpClients.Find(key);
|
||||
connectionID = udpClient->getConnectionID();
|
||||
FString info = "Connection already present:" + domain + ":" + FString::FromInt(port);
|
||||
onsocketClientUDPConnectionEventDelegate.Broadcast(true,info , connectionID);
|
||||
if (udpInitAsyncNode != nullptr) {
|
||||
udpInitAsyncNode->triggerInitEvent(true, connectionID, info);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
USocketClientUDP* udpClient = NewObject<USocketClientUDP>(USocketClientUDP::StaticClass());
|
||||
connectionID = FGuid::NewGuid().ToString();
|
||||
udpClients.Add(connectionID, udpClient);
|
||||
udpClients.Add(key, udpClient);
|
||||
udpClient->init(this, udpInitAsyncNode, domain, ipType, port, receiveFilter, connectionID, maxPacketSize);
|
||||
}
|
||||
|
||||
|
||||
void USocketClientBPLibrary::socketClientSendUDP(FString domainOrIP, ESocketClientIPType ipType, int32 port, FString message, TArray<uint8> byteArray, bool addLineBreak, FString connectionID){
|
||||
USocketClientBPLibrary::getSocketClientTarget()->socketClientSendUDPNonStatic(domainOrIP, ipType, port, message, byteArray, addLineBreak, connectionID);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::socketClientSendUDPNonStatic(FString domain, ESocketClientIPType ipType, int32 port, FString message, TArray<uint8> byteArray, bool addLineBreak, FString clientConnectionIDP) {
|
||||
|
||||
if (clientConnectionIDP.IsEmpty() || udpClients.Find(clientConnectionIDP) == nullptr) {
|
||||
//don't send to many error messages. one second = 10000000 ticks
|
||||
if (((FDateTime::Now().GetTicks()) - lastErrorMessageTime) >= 10000000) {
|
||||
UE_LOG(LogTemp, Error, TEXT("Connection not found (socketClientSendUDPMessage). %s"), *clientConnectionIDP);
|
||||
lastErrorMessageTime = FDateTime::Now().GetTicks();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.Len() > 0 && addLineBreak) {
|
||||
message.Append("\r\n");
|
||||
}
|
||||
USocketClientUDP* udpClient = *udpClients.Find(clientConnectionIDP);
|
||||
udpClient->sendUDPMessage(domain, ipType, port, message, byteArray);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void USocketClientBPLibrary::closeSocketClientConnectionUDP(FString connectionID){
|
||||
USocketClientBPLibrary::getSocketClientTarget()->closeSocketClientConnectionUDPNonStatic(connectionID);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::closeSocketClientConnectionUDPNonStatic(FString connectionID) {
|
||||
if (connectionID.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (udpClients.Find(connectionID) == nullptr) {
|
||||
UE_LOG(LogTemp, Warning, TEXT("Connection not found (closeSocketClientUDPConnection). %s"), *connectionID);
|
||||
return;
|
||||
}
|
||||
|
||||
USocketClientUDP* udpClient = *udpClients.Find(connectionID);
|
||||
udpClient->closeUDPConnection();
|
||||
udpClients.Remove(connectionID);
|
||||
|
||||
FString key = udpClient->getDomainOrIP() + FString::FromInt(udpClient->getPort());
|
||||
udpClients.Remove(key);
|
||||
udpClient = nullptr;
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::getUDPInitializationByConnectionID(FString connectionID, bool& found, USocketClientUDP*& connection){
|
||||
USocketClientBPLibrary::getSocketClientTarget()->getUDPInitializationByConnectionIDNonStatic(connectionID, found, connection);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::getUDPInitializationByConnectionIDNonStatic(FString connectionID, bool& found, USocketClientUDP*& connection){
|
||||
if (connectionID.IsEmpty() || udpClients.Find(connectionID) == nullptr) {
|
||||
found = false;
|
||||
connection = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
found = true;
|
||||
connection = *udpClients.Find(connectionID);
|
||||
}
|
||||
|
||||
bool USocketClientBPLibrary::isUDPInitialized(FString connectionID){
|
||||
return USocketClientBPLibrary::getSocketClientTarget()->isUDPInitializedNonStatic(connectionID);
|
||||
}
|
||||
|
||||
bool USocketClientBPLibrary::isUDPInitializedNonStatic(FString connectionID){
|
||||
if (connectionID.IsEmpty() || udpClients.Find(connectionID) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (*udpClients.Find(connectionID))->isRun();
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::changeSocketPlatform(ESocketPlatformClient platform) {
|
||||
USocketClientBPLibrary::getSocketClientTarget()->systemSocketPlatform = platform;
|
||||
}
|
||||
|
||||
FString USocketClientBPLibrary::resolveDomain(FString serverDomainP, ESocketClientIPType ipType) {
|
||||
|
||||
FString* cachedDomainPointer = domainCache.Find(serverDomainP);
|
||||
if (cachedDomainPointer != nullptr) {
|
||||
return *cachedDomainPointer;
|
||||
}
|
||||
|
||||
//is IPv4?
|
||||
if (ipType == ESocketClientIPType::E_ipv4) {
|
||||
TArray<FString> ipNumbers;
|
||||
int32 lineCount = serverDomainP.ParseIntoArray(ipNumbers, TEXT("."), true);
|
||||
if (lineCount == 4 && serverDomainP.Len() <= 15 && serverDomainP.Len() >= 7) {
|
||||
domainCache.Add(serverDomainP, serverDomainP);
|
||||
return serverDomainP;
|
||||
}
|
||||
}
|
||||
|
||||
//is IPv6? Just a simple check
|
||||
if (ipType == ESocketClientIPType::E_ipv6) {
|
||||
TArray<FString> ipNumbers;
|
||||
int32 lineCount = serverDomainP.ParseIntoArray(ipNumbers, TEXT(":"), true);
|
||||
if (lineCount >= 2) {
|
||||
domainCache.Add(serverDomainP, serverDomainP);
|
||||
return serverDomainP;
|
||||
}
|
||||
}
|
||||
|
||||
//resolve Domain
|
||||
ISocketSubsystem* sSS = USocketClientBPLibrary::getSocketSubSystem();
|
||||
|
||||
FResolveInfo* ResolveInfo = sSS->GetHostByName(TCHAR_TO_ANSI(*serverDomainP));
|
||||
while (!ResolveInfo->IsComplete());
|
||||
|
||||
int32 errorCode = ResolveInfo->GetErrorCode();
|
||||
if (errorCode == 0) {
|
||||
const FInternetAddr* Addr = &ResolveInfo->GetResolvedAddress();
|
||||
uint32 OutIP = 0;
|
||||
FString adr = Addr->ToString(false);
|
||||
domainCache.Add(serverDomainP, adr);
|
||||
return adr;
|
||||
}
|
||||
else {
|
||||
if (dnsClient == nullptr)
|
||||
dnsClient = NewObject<UDNSClientSocketClient>(UDNSClientSocketClient::StaticClass());
|
||||
dnsClient->resolveDomain(sSS, serverDomainP);
|
||||
int32 timeout = 1000;
|
||||
while (dnsClient->isResloving() && timeout > 0) {
|
||||
timeout -= 10;
|
||||
FPlatformProcess::Sleep(0.01);
|
||||
}
|
||||
FString adr = dnsClient->getIP();
|
||||
domainCache.Add(serverDomainP, adr);
|
||||
return adr;
|
||||
}
|
||||
|
||||
return serverDomainP;
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::cleanConnection(FSocketClientPluginSession& session){
|
||||
socketClientCleanerThread->addSession(session);
|
||||
}
|
||||
|
||||
|
||||
void USocketClientBPLibrary::changeCleanerThreadSettingsOnClient(bool showLogs, int32 minLiveTimeInSeconds){
|
||||
if (USocketClientBPLibrary::getSocketClientTarget()->socketClientCleanerThread != nullptr) {
|
||||
USocketClientBPLibrary::getSocketClientTarget()->socketClientCleanerThread->changeSettings(showLogs, minLiveTimeInSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::getSystemType(ESocketClientSystem& system) {
|
||||
#if PLATFORM_ANDROID
|
||||
system = ESocketClientSystem::Android;
|
||||
return;
|
||||
#endif
|
||||
#if PLATFORM_IOS
|
||||
system = ESocketClientSystem::IOS;
|
||||
return;
|
||||
#endif
|
||||
#if PLATFORM_WINDOWS
|
||||
system = ESocketClientSystem::Windows;
|
||||
return;
|
||||
#endif
|
||||
#if PLATFORM_LINUX
|
||||
system = ESocketClientSystem::Linux;
|
||||
return;
|
||||
#endif
|
||||
#if PLATFORM_MAC
|
||||
system = ESocketClientSystem::Mac;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
TArray<uint8> USocketClientBPLibrary::parseHexToBytes(FString hex) {
|
||||
TArray<uint8> bytes;
|
||||
|
||||
if (hex.Contains(" ")) {
|
||||
hex = hex.Replace(TEXT(" "), TEXT(""));
|
||||
}
|
||||
|
||||
if (hex.Len() % 2 != 0) {
|
||||
UE_LOG(LogTemp, Error, TEXT("This is not a valid hex string: %s"), *hex);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
TArray<TCHAR> charArray = hex.GetCharArray();
|
||||
for (int32 i = 0; i < (charArray.Num() - 1); i++) {
|
||||
if (CheckTCharIsHex(charArray[i]) == false) {
|
||||
UE_LOG(LogTemp, Error, TEXT("This is not a valid hex string: %s"), *hex);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bytes.AddZeroed(hex.Len() / 2);
|
||||
HexToBytes(hex, bytes.GetData());
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
FString USocketClientBPLibrary::parseHexToString(FString hex) {
|
||||
TArray<uint8> bytes = parseHexToBytes(hex);
|
||||
bytes.Add(0x00);// null-terminator
|
||||
char* Data = (char*)bytes.GetData();
|
||||
return FString(UTF8_TO_TCHAR(Data));
|
||||
}
|
||||
|
||||
FString USocketClientBPLibrary::parseBytesToHex(TArray<uint8> bytes) {
|
||||
FString hex;
|
||||
hex = BytesToHex(bytes.GetData(), bytes.Num());
|
||||
return hex;
|
||||
}
|
||||
|
||||
TArray<uint8> USocketClientBPLibrary::parseHexToBytesPure(FString hex) {
|
||||
return parseHexToBytes(hex);
|
||||
}
|
||||
|
||||
FString USocketClientBPLibrary::parseHexToStringPure(FString hex) {
|
||||
return parseHexToString(hex);
|
||||
}
|
||||
|
||||
FString USocketClientBPLibrary::parseBytesToHexPure(TArray<uint8> bytes) {
|
||||
return parseBytesToHex(bytes);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToFloat(TArray<uint8> bytes, float& value) {
|
||||
|
||||
if (bytes.Num() != 4) {
|
||||
UE_LOG(LogTemp, Error, TEXT("ParseBytesToFloat: Cannot convert bytes to float. Array must contain 4 bytes but has %i bytes."), bytes.Num());
|
||||
return;
|
||||
}
|
||||
|
||||
FMemory::Memcpy(&value, bytes.GetData(), 4);
|
||||
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToInteger(TArray<uint8> bytes, int32& value) {
|
||||
|
||||
|
||||
if (bytes.Num() != 4) {
|
||||
UE_LOG(LogTemp, Error, TEXT("ParseBytesToInteger: Cannot convert bytes to integer. Array must contain 4 bytes but has %i bytes."), bytes.Num());
|
||||
return;
|
||||
}
|
||||
|
||||
FMemory::Memcpy(&value, bytes.GetData(), 4);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToInteger64(TArray<uint8> bytes, int64& value) {
|
||||
|
||||
|
||||
if (bytes.Num() != 8) {
|
||||
UE_LOG(LogTemp, Error, TEXT("ParseBytesToInteger64: Cannot convert bytes to integer. Array must contain 8 bytes but has %i bytes."), bytes.Num());
|
||||
return;
|
||||
}
|
||||
|
||||
FMemory::Memcpy(&value, bytes.GetData(), 8);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToFloatPure(TArray<uint8> bytes, float& value){
|
||||
parseBytesToFloat(bytes, value);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToIntegerPure(TArray<uint8> bytes, int32& value){
|
||||
parseBytesToInteger(bytes, value);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToInteger64Pure(TArray<uint8> bytes, int64& value){
|
||||
parseBytesToInteger64(bytes, value);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToFloatEndian(TArray<uint8> bytes, float& littleEndian, float& bigEndian) {
|
||||
littleEndian = 0.f;
|
||||
bigEndian = 0.f;
|
||||
|
||||
if (bytes.Num() != 4) {
|
||||
UE_LOG(LogTemp, Error, TEXT("ParseBytesToFloat: Cannot convert bytes to float. Array must contain 4 bytes but has %i bytes."), bytes.Num());
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 littleEndianChar[] = { bytes[0], bytes[1], bytes[2], bytes[3] };
|
||||
FMemory::Memcpy(&littleEndian, &littleEndianChar, sizeof(littleEndian));
|
||||
|
||||
uint8 bigEndianChar[] = { bytes[3], bytes[2], bytes[1], bytes[0] };
|
||||
FMemory::Memcpy(&bigEndian, &bigEndianChar, sizeof(bigEndian));
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToIntegerEndian(TArray<uint8> bytes, int32& littleEndian, int32& bigEndian){
|
||||
littleEndian = 0;
|
||||
bigEndian = 0;
|
||||
|
||||
if (bytes.Num() != 4){
|
||||
UE_LOG(LogTemp, Error, TEXT("ParseBytesToInteger: Cannot convert bytes to integer. Array must contain 4 bytes but has %i bytes."), bytes.Num());
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
uint8 littleEndianChar[] = { bytes[0], bytes[1], bytes[2], bytes[3] };
|
||||
FMemory::Memcpy(&littleEndian, &littleEndianChar, sizeof(littleEndian));
|
||||
|
||||
uint8 bigEndianChar[] = { bytes[3], bytes[2], bytes[1], bytes[0] };
|
||||
FMemory::Memcpy(&bigEndian, &bigEndianChar, sizeof(bigEndian));
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToInteger64Endian(TArray<uint8> bytes, int64& littleEndian, int64& bigEndian) {
|
||||
littleEndian = 0;
|
||||
bigEndian = 0;
|
||||
|
||||
if (bytes.Num() != 8) {
|
||||
UE_LOG(LogTemp, Error, TEXT("ParseBytesToInteger64: Cannot convert bytes to integer. Array must contain 8 bytes but has %i bytes."), bytes.Num());
|
||||
return;
|
||||
}return;
|
||||
|
||||
uint8 littleEndianChar[] = { bytes[0], bytes[1], bytes[2], bytes[3],bytes[4], bytes[5], bytes[6], bytes[7] };
|
||||
FMemory::Memcpy(&littleEndian, &littleEndianChar, sizeof(littleEndian));
|
||||
|
||||
uint8 bigEndianChar[] = { bytes[7], bytes[6], bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0] };
|
||||
FMemory::Memcpy(&bigEndian, &bigEndianChar, sizeof(bigEndian));
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseFloatToBytes(TArray<uint8>& byteArray, float value, bool switchByteOrder){
|
||||
union {
|
||||
float tmpVal;
|
||||
uint8 tmpArray[4];
|
||||
} u;
|
||||
u.tmpVal = value;
|
||||
byteArray.AddUninitialized(4);
|
||||
|
||||
FMemory::Memcpy(byteArray.GetData(), u.tmpArray, 4);
|
||||
|
||||
if (switchByteOrder) {
|
||||
byteArray.SwapMemory(3, 0);
|
||||
byteArray.SwapMemory(2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseIntegerToBytes(TArray<uint8>& byteArray, int32 value, bool switchByteOrder){
|
||||
union {
|
||||
int32 tmpVal;
|
||||
uint8 tmpArray[4];
|
||||
} u;
|
||||
u.tmpVal = value;
|
||||
byteArray.AddUninitialized(4);
|
||||
|
||||
FMemory::Memcpy(byteArray.GetData(), u.tmpArray, 4);
|
||||
|
||||
if (switchByteOrder) {
|
||||
byteArray.SwapMemory(3, 0);
|
||||
byteArray.SwapMemory(2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseInteger64ToBytes(TArray<uint8>& byteArray, int64 value, bool switchByteOrder){
|
||||
union {
|
||||
int64 tmpVal;
|
||||
uint8 tmpArray[8];
|
||||
} u;
|
||||
u.tmpVal = value;
|
||||
byteArray.AddUninitialized(8);
|
||||
|
||||
FMemory::Memcpy(byteArray.GetData(), u.tmpArray, 8);
|
||||
|
||||
if (switchByteOrder) {
|
||||
byteArray.SwapMemory(7, 0);
|
||||
byteArray.SwapMemory(6, 1);
|
||||
byteArray.SwapMemory(5, 2);
|
||||
byteArray.SwapMemory(4, 3);
|
||||
}
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseFloatToBytesPure(TArray<uint8>& byteArray, float value, bool switchByteOrder){
|
||||
parseFloatToBytes(byteArray, value, switchByteOrder);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseIntegerToBytesPure(TArray<uint8>& byteArray, int32 value, bool switchByteOrder){
|
||||
parseIntegerToBytes(byteArray, value, switchByteOrder);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseInteger64ToBytesPure(TArray<uint8>& byteArray, int64 value, bool switchByteOrder){
|
||||
parseInteger64ToBytes(byteArray, value, switchByteOrder);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToFloatArrayPure(TArray<float>& value, TArray<uint8> bytes) {
|
||||
if (bytes.Num() == 0 && bytes.Num() % 4 != 0)
|
||||
return;
|
||||
value.Empty();
|
||||
value.AddUninitialized(bytes.Num() / 4);
|
||||
FMemory::Memcpy(value.GetData(), bytes.GetData(), bytes.Num());
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToIntegerArrayPure(TArray<int32>& value, TArray<uint8> bytes) {
|
||||
if (bytes.Num() == 0 && bytes.Num() % 4 != 0)
|
||||
return;
|
||||
value.Empty();
|
||||
value.AddUninitialized(bytes.Num() / 4);
|
||||
FMemory::Memcpy(value.GetData(), bytes.GetData(), bytes.Num());
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseBytesToInteger64ArrayPure(TArray<int64>& value, TArray<uint8> bytes) {
|
||||
if (bytes.Num() == 0 && bytes.Num() % 8 != 0)
|
||||
return;
|
||||
value.Empty();
|
||||
value.AddUninitialized(bytes.Num() / 8);
|
||||
FMemory::Memcpy(value.GetData(), bytes.GetData(), bytes.Num());
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseFloatArrayToBytesPure(TArray<uint8>& byteArray, TArray<float> value) {
|
||||
byteArray.Empty();
|
||||
byteArray.AddUninitialized(value.Num() * 4);
|
||||
FMemory::Memcpy(byteArray.GetData(), value.GetData(), value.Num() * 4);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseIntegerArrayToBytesPure(TArray<uint8>& byteArray, TArray<int32> value) {
|
||||
byteArray.Empty();
|
||||
byteArray.AddUninitialized(value.Num() * 4);
|
||||
FMemory::Memcpy(byteArray.GetData(), value.GetData(), value.Num() * 4);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::parseInteger64ArrayToBytesPure(TArray<uint8>& byteArray, TArray<int64> value) {
|
||||
byteArray.Empty();
|
||||
byteArray.AddUninitialized(value.Num() * 8);
|
||||
FMemory::Memcpy(byteArray.GetData(), value.GetData(), value.Num() * 8);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::changeTCPSeparatorStringOnClient(FString separator) {
|
||||
USocketClientBPLibrary::getSocketClientTarget()->changeTCPSeparatorStringOnClientNonStatic(separator);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::changeTCPSeparatorStringOnClientNonStatic(FString separator) {
|
||||
tcpStringSeparator = separator;
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::changeTCPSeparatorByteOnClient(uint8 separator) {
|
||||
USocketClientBPLibrary::getSocketClientTarget()->changeTCPSeparatorByteOnClientNonStatic(separator);
|
||||
}
|
||||
|
||||
void USocketClientBPLibrary::changeTCPSeparatorByteOnClientNonStatic(uint8 separator) {
|
||||
tcpByteSeparator = separator;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int32 USocketClientBPLibrary::getUniquePlayerID(APlayerController* playerController) {
|
||||
if (playerController == nullptr || playerController->GetLocalPlayer() == nullptr)
|
||||
return 0;
|
||||
return playerController->GetLocalPlayer()->GetUniqueID();
|
||||
}
|
||||
|
||||
FString USocketClientBPLibrary::getRandomID(){
|
||||
return FGuid::NewGuid().ToString();
|
||||
}
|
||||
|
||||
|
||||
void USocketClientBPLibrary::getTcpSeparator(uint8& byteSeparator, FString& stringSeparator){
|
||||
stringSeparator = tcpStringSeparator;
|
||||
byteSeparator = tcpByteSeparator;
|
||||
}
|
||||
|
||||
ISocketSubsystem* USocketClientBPLibrary::getSocketSubSystem() {
|
||||
switch (USocketClientBPLibrary::getSocketClientTarget()->systemSocketPlatform)
|
||||
{
|
||||
case ESocketPlatformClient::E_SSC_SYSTEM:
|
||||
return ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
|
||||
case ESocketPlatformClient::E_SSC_WINDOWS:
|
||||
return ISocketSubsystem::Get(FName(TEXT("WINDOWS")));
|
||||
case ESocketPlatformClient::E_SSC_MAC:
|
||||
return ISocketSubsystem::Get(FName(TEXT("MAC")));
|
||||
case ESocketPlatformClient::E_SSC_IOS:
|
||||
return ISocketSubsystem::Get(FName(TEXT("IOS")));
|
||||
case ESocketPlatformClient::E_SSC_UNIX:
|
||||
return ISocketSubsystem::Get(FName(TEXT("UNIX")));
|
||||
case ESocketPlatformClient::E_SSC_ANDROID:
|
||||
return ISocketSubsystem::Get(FName(TEXT("ANDROID")));
|
||||
case ESocketPlatformClient::E_SSC_PS4:
|
||||
return ISocketSubsystem::Get(FName(TEXT("PS4")));
|
||||
case ESocketPlatformClient::E_SSC_XBOXONE:
|
||||
return ISocketSubsystem::Get(FName(TEXT("XBOXONE")));
|
||||
case ESocketPlatformClient::E_SSC_HTML5:
|
||||
return ISocketSubsystem::Get(FName(TEXT("HTML5")));
|
||||
case ESocketPlatformClient::E_SSC_SWITCH:
|
||||
return ISocketSubsystem::Get(FName(TEXT("SWITCH")));
|
||||
case ESocketPlatformClient::E_SSC_DEFAULT:
|
||||
return ISocketSubsystem::Get();
|
||||
default:
|
||||
return ISocketSubsystem::Get(PLATFORM_SOCKETSUBSYSTEM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
// Copyright 2022 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#include "SocketClientCleanerThread.h"
|
||||
|
||||
FSocketClientCleanerThread::FSocketClientCleanerThread() {
|
||||
FString threadName = "FSocketClientPluginCleanerThread_" + FGuid::NewGuid().ToString();
|
||||
thread = FRunnableThread::Create(this, *threadName, 0, EThreadPriority::TPri_Lowest);
|
||||
}
|
||||
|
||||
|
||||
void FSocketClientCleanerThread::addSession(FSocketClientPluginSession& session) {
|
||||
session.addToCleanerTime = FDateTime::Now().GetTicks();
|
||||
sessionQueue.Enqueue(session);
|
||||
}
|
||||
|
||||
void FSocketClientCleanerThread::changeSettings(bool showLogsP, int32 minLiveTimeInSecondsP) {
|
||||
showLogs = showLogsP;
|
||||
minLiveTimeInSeconds = minLiveTimeInSecondsP;
|
||||
}
|
||||
|
||||
uint32 FSocketClientCleanerThread::Run() {
|
||||
while (true) {
|
||||
TArray<FSocketClientPluginSession> tryItAgain;
|
||||
|
||||
if (showLogs && sessionQueue.IsEmpty()) {
|
||||
UE_LOG(LogTemp, Display, TEXT("SocketClient: Cleaner: No connections available to clean up."));
|
||||
}
|
||||
|
||||
while (sessionQueue.IsEmpty() == false) {
|
||||
FSocketClientPluginSession session;
|
||||
sessionQueue.Dequeue(session);
|
||||
|
||||
|
||||
//one second = 10000000 ticks
|
||||
if ((FDateTime::Now().GetTicks() - session.addToCleanerTime) < (10000000 * minLiveTimeInSeconds)) {
|
||||
tryItAgain.Add(session);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (showLogs) {
|
||||
UE_LOG(LogTemp, Display, TEXT("SocketClient: Clean connection: %s"), *session.clientID);
|
||||
}
|
||||
|
||||
|
||||
delete session.tcpSendThread;
|
||||
delete session.tcpRecieverThread;
|
||||
|
||||
delete session.tcpFileHandlerThread;
|
||||
|
||||
delete session.udpSocketReceiver;
|
||||
delete session.udpSendDataThead;
|
||||
delete session.udpReceiveDataThread;
|
||||
|
||||
delete session.socket;
|
||||
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < tryItAgain.Num(); i++) {
|
||||
sessionQueue.Enqueue(tryItAgain[i]);
|
||||
}
|
||||
tryItAgain.Empty();
|
||||
|
||||
|
||||
FPlatformProcess::Sleep(minLiveTimeInSeconds);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#include "SocketClientTCP.h"
|
||||
|
||||
|
||||
USocketClientTCPClient::USocketClientTCPClient(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {
|
||||
//This prevents the garbage collector from killingand deleting the class from RAM.
|
||||
this->AddToRoot();
|
||||
onsocketClientTCPConnectionEventDelegate.AddDynamic(this, &USocketClientTCPClient::connectionEvent);
|
||||
}
|
||||
|
||||
|
||||
void USocketClientTCPClient::socketClientTCPConnectionEventDelegate(const bool success, const FString message, const FString clientConnectionID) {}
|
||||
void USocketClientTCPClient::receiveTCPMessageEventDelegate(const FString message, const TArray<uint8>& byteArray, const FString clientConnectionID){}
|
||||
void USocketClientTCPClient::transferFileOverTCPProgressEventDelegate(const FString clientConnectionID, const FString filePathP, const float percent, const float mbit, const int64 bytesTransferred, const int64 fileSize) {}
|
||||
void USocketClientTCPClient::fileTransferOverTCPInfoEventDelegate(const FString message, const FString clientConnectionID, const FString filePathP, const bool success) {}
|
||||
|
||||
void USocketClientTCPClient::connectionEvent(bool success, FString message, FString clientConnectionID){
|
||||
connected = success;
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::connect(USocketClientBPLibrary* mainLibP, FString domainOrIP, ESocketClientIPType ipType, int32 port, EReceiveFilterClient receiveFilter,
|
||||
ESocketClientTCPSeparator messageWrappingP, FString connectionIDP, UTCPConnectAsyncNode* tcpConnectAsyncNodeP, bool noPacketDelay, bool noPacketBlocking){
|
||||
mainLib = mainLibP;
|
||||
connectionID = connectionIDP;
|
||||
messageWrapping = messageWrappingP;
|
||||
tcpConnectAsyncNode = tcpConnectAsyncNodeP;
|
||||
USocketClientBPLibrary::socketClientBPLibrary->getTcpSeparator(tcpByteSeparator, tcpStringSeparator);
|
||||
tcpReceiveDataThread = new FSocketClientTCPReceiveDataThread(mainLib, connectionID, receiveFilter, domainOrIP, ipType, port,this,noPacketDelay,noPacketBlocking);
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::sendMessage(FString message, TArray<uint8> byteArray){
|
||||
if (run && tcpSendThread != nullptr) {
|
||||
tcpSendThread->sendMessage(message, byteArray);
|
||||
}
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::sendFile(USocketClientBPLibrary* mainLibP, FString connectionIDP, FString domainOrIP, ESocketClientIPType ipType, int32 port, EFileFunctionsSocketClientDirectoryType directoryType, FString filePathP, FString token, FString Aes256bitKey){
|
||||
mainLib = mainLibP;
|
||||
connectionID = connectionIDP;
|
||||
aesKey = Aes256bitKey;
|
||||
fileToken = token;
|
||||
sendOrReceive = 0;
|
||||
filePath = UFileFunctionsSocketClient::getCleanDirectory(directoryType, filePathP);
|
||||
tcpFileConnectionThread = new FSocketClientTCPFileHandlerThread(mainLib, connectionID, domainOrIP, ipType, port, this);
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::requestFile(USocketClientBPLibrary* mainLibP, FString connectionIDP, FString domainOrIP, ESocketClientIPType ipType, int32 port, EFileFunctionsSocketClientDirectoryType directoryType, FString filePathP, bool resumeP, FString token, FString Aes256bitKey) {
|
||||
mainLib = mainLibP;
|
||||
connectionID = connectionIDP;
|
||||
aesKey = Aes256bitKey;
|
||||
fileToken = token;
|
||||
sendOrReceive = 1;
|
||||
resume = resumeP;
|
||||
filePath = UFileFunctionsSocketClient::getCleanDirectory(directoryType, filePathP);
|
||||
tcpFileConnectionThread = new FSocketClientTCPFileHandlerThread(mainLib, connectionID, domainOrIP, ipType, port, this);
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::closeConnection(){
|
||||
|
||||
setRun(false);
|
||||
|
||||
if (tcpFileConnectionThread != nullptr) {
|
||||
tcpFileConnectionThread->triggerFileTransferOverTCPInfoEvent("Data transfer aborted.", connectionID, filePath, false, mainLib, this);
|
||||
}
|
||||
|
||||
if (tcpSendThread != nullptr) {
|
||||
tcpSendThread->pauseThread(false);
|
||||
}
|
||||
|
||||
|
||||
if (mainLib != nullptr) {
|
||||
FSocketClientPluginSession connectionSession = FSocketClientPluginSession();
|
||||
connectionSession.tcpRecieverThread = tcpReceiveDataThread;
|
||||
connectionSession.tcpSendThread = tcpSendThread;
|
||||
//connectionSession.tcpSendFileThread = fileSendThread;
|
||||
connectionSession.tcpFileHandlerThread = tcpFileConnectionThread;
|
||||
connectionSession.socket = socket;
|
||||
connectionSession.clientID = connectionID;
|
||||
mainLib->cleanConnection(connectionSession);
|
||||
}
|
||||
}
|
||||
|
||||
bool USocketClientTCPClient::isRun(){
|
||||
return run;
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::setRun(bool runP) {
|
||||
run = runP;
|
||||
}
|
||||
|
||||
FString USocketClientTCPClient::getConnectionID(){
|
||||
return connectionID;
|
||||
}
|
||||
|
||||
FString USocketClientTCPClient::getAesKey(){
|
||||
return aesKey;
|
||||
}
|
||||
|
||||
FString USocketClientTCPClient::getFileToken(){
|
||||
return fileToken;
|
||||
}
|
||||
|
||||
FString USocketClientTCPClient::getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::setSocket(FSocket* socketP){
|
||||
socket = socketP;
|
||||
}
|
||||
|
||||
FSocket* USocketClientTCPClient::getSocket(){
|
||||
return socket;
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::createSendThread(){
|
||||
tcpSendThread = new FSocketClientTCPSendDataThead(mainLib, this, connectionID);
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::getTcpSeparator(FString& stringSeparator, uint8& byteSeparator, ESocketClientTCPSeparator& messageWrappingP) {
|
||||
messageWrappingP = messageWrapping;
|
||||
stringSeparator = tcpStringSeparator;
|
||||
tcpByteSeparator = byteSeparator;
|
||||
}
|
||||
|
||||
FString USocketClientTCPClient::encryptMessage(FString message) {
|
||||
return UFileFunctionsSocketClient::encryptMessageWithAES(message, aesKey);
|
||||
}
|
||||
|
||||
FString USocketClientTCPClient::decryptMessage(FString message) {
|
||||
return UFileFunctionsSocketClient::decryptMessageWithAES(message, aesKey);
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::readDataLength(TArray<uint8>& byteDataArray, int32& byteLenght) {
|
||||
if (FGenericPlatformProperties::IsLittleEndian() && byteDataArray[0] == 0x00) {
|
||||
FMemory::Memcpy(&byteLenght, byteDataArray.GetData() + 1, 4);
|
||||
}
|
||||
else {
|
||||
//endian fits not. swap bytes that contains the length
|
||||
byteDataArray.SwapMemory(1, 4);
|
||||
byteDataArray.SwapMemory(2, 3);
|
||||
FMemory::Memcpy(&byteLenght, byteDataArray.GetData() + 1, 4);
|
||||
}
|
||||
}
|
||||
|
||||
bool USocketClientTCPClient::isSendFile(){
|
||||
return (sendOrReceive == 0);
|
||||
}
|
||||
|
||||
bool USocketClientTCPClient::isReceiveFile(){
|
||||
return (sendOrReceive == 1);
|
||||
}
|
||||
|
||||
bool USocketClientTCPClient::hasResume(){
|
||||
return resume;
|
||||
}
|
||||
|
||||
bool USocketClientTCPClient::isConnected()
|
||||
{
|
||||
return connected;
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::deleteFile(FString filePathP){
|
||||
UFileFunctionsSocketClient::deleteFileAbsolutePath(filePathP);
|
||||
}
|
||||
|
||||
void USocketClientTCPClient::getMD5FromFileAbsolutePath(FString filePathP, bool& success, FString& MD5) {
|
||||
UFileFunctionsSocketClient::getMD5FromFileAbsolutePath(filePathP, success, MD5);
|
||||
}
|
||||
|
||||
int64 USocketClientTCPClient::fileSize(FString filePathP) {
|
||||
return UFileFunctionsSocketClient::fileSizeAbsolutePath(filePathP);
|
||||
}
|
||||
|
||||
USocketClientBPLibrary* USocketClientTCPClient::getMainLib() {
|
||||
return mainLib;
|
||||
}
|
||||
|
||||
FString USocketClientTCPClient::int64ToString(int64 num) {
|
||||
return UFileFunctionsSocketClient::int64ToString(num);
|
||||
}
|
||||
+592
@@ -0,0 +1,592 @@
|
||||
// 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;
|
||||
}
|
||||
+288
@@ -0,0 +1,288 @@
|
||||
// Copyright 2022 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#include "SocketClientTCPReceiveDataThread.h"
|
||||
|
||||
|
||||
FSocketClientTCPReceiveDataThread::FSocketClientTCPReceiveDataThread(USocketClientBPLibrary* socketClientBPLibraryP, FString clientConnectionIDP,
|
||||
EReceiveFilterClient receiveFilterP, FString ipOrDomainP, ESocketClientIPType ipTypeP, int32 portP,
|
||||
USocketClientTCPClient* tcpClientP, bool noPacketDelayP, bool noPacketBlockingP) :
|
||||
socketClientBPLibrary(socketClientBPLibraryP),
|
||||
clientConnectionID(clientConnectionIDP),
|
||||
receiveFilter(receiveFilterP),
|
||||
ipOrDomain(ipOrDomainP),
|
||||
ipType(ipTypeP),
|
||||
port(portP),
|
||||
tcpClient(tcpClientP),
|
||||
noPacketDelay(noPacketDelayP),
|
||||
noPacketBlocking(noPacketBlockingP) {
|
||||
FString threadName = "FServerConnectionThread" + FGuid::NewGuid().ToString();
|
||||
thread = FRunnableThread::Create(this, *threadName, 0, EThreadPriority::TPri_Normal);
|
||||
}
|
||||
|
||||
FSocketClientTCPReceiveDataThread::~FSocketClientTCPReceiveDataThread() {
|
||||
if (tcpClient != nullptr && tcpClient->tcpConnectAsyncNode != nullptr) {
|
||||
tcpClient->tcpConnectAsyncNode = nullptr;
|
||||
}
|
||||
delete thread;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint32 FSocketClientTCPReceiveDataThread::Run() {
|
||||
//UE_LOG(LogTemp, Display, TEXT("DoWork:%s"),*(FDateTime::Now()).ToString());
|
||||
FString ip = socketClientBPLibrary->resolveDomain(ipOrDomain, ipType);
|
||||
int32 portGlobal = port;
|
||||
FString clientConnectionIDGlobal = clientConnectionID;
|
||||
USocketClientBPLibrary* socketClientGlobal = socketClientBPLibrary;
|
||||
USocketClientTCPClient* tcpClientGlobal = tcpClient;
|
||||
|
||||
//message wrapping
|
||||
FString stringSeparator = FString();
|
||||
uint8 byteSeparator = 0x00;
|
||||
ESocketClientTCPSeparator messageWrapping = ESocketClientTCPSeparator::E_None;
|
||||
tcpClient->getTcpSeparator(stringSeparator, byteSeparator, messageWrapping);
|
||||
|
||||
TArray<TCHAR> stringSeparatorArray = stringSeparator.GetCharArray();
|
||||
if (stringSeparatorArray.Num() > 0 && stringSeparatorArray.Last() == 0x00) {
|
||||
stringSeparatorArray.RemoveAt(stringSeparatorArray.Num() - 1, 1, true);
|
||||
}
|
||||
|
||||
if (messageWrapping == ESocketClientTCPSeparator::E_LengthSeparator && stringSeparatorArray.Num() == 0) {
|
||||
messageWrapping = ESocketClientTCPSeparator::E_None;
|
||||
UE_LOG(LogTemp, Warning, TEXT("Socket Client Plugin: Separator mode is set to String but there is no String Separator. Mode changed to none."));
|
||||
}
|
||||
|
||||
|
||||
//UE_LOG(LogTemp, Warning, TEXT("Tread:%s:%i"),*ip, port);
|
||||
ISocketSubsystem* sSS = USocketClientBPLibrary::getSocketSubSystem();
|
||||
if (sSS == nullptr) {
|
||||
FString info = "Connection failed(1). SocketSubSystem does not exist.:" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal;
|
||||
triggerConnectionEvent(false, clientConnectionID, info, tcpClientGlobal, socketClientGlobal);
|
||||
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);
|
||||
|
||||
|
||||
//socket options
|
||||
if (socket != nullptr) {
|
||||
socket->SetNoDelay(noPacketDelay);
|
||||
socket->SetNonBlocking(noPacketBlocking);
|
||||
|
||||
tcpClient->setRun(true);
|
||||
}
|
||||
|
||||
// try to connect to the server
|
||||
if (socket == nullptr || socket->Connect(*addr) == false) {
|
||||
const TCHAR* socketErr = sSS->GetSocketError(SE_GET_LAST_ERROR_CODE);
|
||||
FString info = "Connection failed(2):" + FString(socketErr) + "|" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal;
|
||||
triggerConnectionEvent(false, clientConnectionID, info, tcpClientGlobal, socketClientGlobal);
|
||||
}
|
||||
else {
|
||||
FString info = "Connection successful:" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal;
|
||||
triggerConnectionEvent(true, clientConnectionID, info, tcpClientGlobal, socketClientGlobal);
|
||||
|
||||
tcpClient->createSendThread();
|
||||
int64 ticks1;
|
||||
int64 ticks2;
|
||||
TArray<uint8> byteDataArray;
|
||||
TArray<uint8> byteDataArrayCache;
|
||||
FString mainMessage;
|
||||
bool inCollectMessageStatus = false;
|
||||
int32 lastDataLengthFromHeader = 0;
|
||||
|
||||
|
||||
uint32 dataSize;
|
||||
while (socket != nullptr && tcpClient->isRun()) {
|
||||
|
||||
//ESocketConnectionState::SCS_Connected does not work https://issues.unrealengine.com/issue/UE-27542
|
||||
//Compare ticks is a workaround to get a disconnect. clientSocket->Wait() stop working after disconnect. (Another bug?)
|
||||
//If it doesn't wait any longer, ticks1 and ticks2 should be the same == disconnect.
|
||||
ticks1 = FDateTime::Now().GetTicks();
|
||||
socket->Wait(ESocketWaitConditions::WaitForRead, FTimespan::FromSeconds(1));
|
||||
ticks2 = FDateTime::Now().GetTicks();
|
||||
|
||||
bool hasData = socket->HasPendingData(dataSize);
|
||||
if (!hasData && ticks1 == ticks2) {
|
||||
UE_LOG(LogTemp, Display, TEXT("Socket Client: Connection aborted or closed by the server: %s"),*clientConnectionID);
|
||||
break;
|
||||
}
|
||||
|
||||
if (hasData) {
|
||||
TArray<uint8> dataFromSocket;
|
||||
dataFromSocket.SetNumUninitialized(dataSize);
|
||||
int32 BytesRead = 0;
|
||||
if (socket->Recv(dataFromSocket.GetData(), dataFromSocket.Num(), BytesRead)) {
|
||||
|
||||
switch (messageWrapping)
|
||||
{
|
||||
case ESocketClientTCPSeparator::E_None:
|
||||
triggerMessageEvent(dataFromSocket, clientConnectionIDGlobal, tcpClientGlobal, socketClientGlobal);
|
||||
break;
|
||||
|
||||
case ESocketClientTCPSeparator::E_ByteSeparator:
|
||||
|
||||
for (int32 i = 0; i < dataFromSocket.Num(); i++) {
|
||||
byteDataArrayCache.Add(dataFromSocket[i]);
|
||||
if (dataFromSocket[i] == byteSeparator) {
|
||||
triggerMessageEvent(byteDataArrayCache, clientConnectionIDGlobal, tcpClientGlobal, socketClientGlobal, false);
|
||||
byteDataArrayCache.Empty();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case ESocketClientTCPSeparator::E_StringSeparator:
|
||||
for (int32 i = 0; i < dataFromSocket.Num(); i++) {
|
||||
;
|
||||
if ((TCHAR)dataFromSocket[i] == stringSeparatorArray[0]) {
|
||||
bool found = true;
|
||||
for (int32 j = 1; j < stringSeparatorArray.Num(); j++) {
|
||||
i++;
|
||||
if (dataFromSocket.Num() <= (i)) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
if ((TCHAR)dataFromSocket[i] != stringSeparatorArray[j]) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
triggerMessageEvent(byteDataArrayCache, clientConnectionIDGlobal, tcpClientGlobal, socketClientGlobal, true);
|
||||
byteDataArrayCache.Empty();
|
||||
}
|
||||
}
|
||||
else {
|
||||
byteDataArrayCache.Add(dataFromSocket[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ESocketClientTCPSeparator::E_LengthSeparator:
|
||||
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);
|
||||
|
||||
|
||||
triggerMessageEvent(byteDataArray, clientConnectionIDGlobal, tcpClientGlobal, socketClientGlobal);
|
||||
//UE_LOG(LogTemp, Display, TEXT("%s"), *mainMessage);
|
||||
byteDataArray.Empty();
|
||||
|
||||
if (byteDataArrayCache.Num() == 0) {
|
||||
lastDataLengthFromHeader = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (byteDataArrayCache.Num() > 5) {
|
||||
tcpClient->readDataLength(byteDataArrayCache, lastDataLengthFromHeader);
|
||||
byteDataArrayCache.RemoveAt(0, 5, true);
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
mainMessage.Empty();
|
||||
byteDataArray.Empty();
|
||||
dataFromSocket.Empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
info = "Connection close:" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal;
|
||||
triggerConnectionEvent(false, clientConnectionID, info, tcpClientGlobal, socketClientGlobal);
|
||||
}
|
||||
|
||||
|
||||
if (socket != nullptr) {
|
||||
socket->Close();
|
||||
}
|
||||
|
||||
if (tcpClient->isRun()) {
|
||||
socketClientBPLibrary->closeSocketClientConnectionTCPNonStatic(clientConnectionID);
|
||||
//tcpClient->closeConnection();
|
||||
}
|
||||
}
|
||||
else {
|
||||
FString info = "Connection failed(3). IP not valid:" + ip + ":" + FString::FromInt(portGlobal) + "|" + clientConnectionIDGlobal;
|
||||
triggerConnectionEvent(false, clientConnectionID,info,tcpClientGlobal, socketClientGlobal);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void FSocketClientTCPReceiveDataThread::triggerConnectionEvent(bool succsess, FString clientConnectionIDGlobal, FString serverMessage, USocketClientTCPClient* tcpClientGlobal, USocketClientBPLibrary* socketClientGlobal){
|
||||
|
||||
AsyncTask(ENamedThreads::GameThread, [succsess, serverMessage, clientConnectionIDGlobal, tcpClientGlobal, socketClientGlobal]() {
|
||||
if (socketClientGlobal != nullptr) {
|
||||
socketClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(succsess, serverMessage, clientConnectionIDGlobal);
|
||||
}
|
||||
if (tcpClientGlobal != nullptr) {
|
||||
tcpClientGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(succsess, serverMessage, clientConnectionIDGlobal);
|
||||
if (tcpClientGlobal->tcpConnectAsyncNode != nullptr) {
|
||||
tcpClientGlobal->tcpConnectAsyncNode->triggerConnectionEvent(succsess, clientConnectionIDGlobal, serverMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FSocketClientTCPReceiveDataThread::triggerMessageEvent(TArray<uint8>& byteDataArray, FString& clientConnectionIDGlobal, USocketClientTCPClient* tcpClientGlobal,
|
||||
USocketClientBPLibrary* socketClientGlobal, bool addNullTerminator) {
|
||||
|
||||
|
||||
FString mainMessage = FString();
|
||||
if (receiveFilter == EReceiveFilterClient::E_SAB || receiveFilter == EReceiveFilterClient::E_S) {
|
||||
if (addNullTerminator)
|
||||
byteDataArray.Add(0x00);// null-terminator
|
||||
mainMessage = FString(UTF8_TO_TCHAR((char*)byteDataArray.GetData()));
|
||||
if (receiveFilter == EReceiveFilterClient::E_S) {
|
||||
byteDataArray.Empty();
|
||||
}
|
||||
}
|
||||
|
||||
//switch to gamethread
|
||||
AsyncTask(ENamedThreads::GameThread, [mainMessage, byteDataArray, clientConnectionIDGlobal, tcpClientGlobal, socketClientGlobal]() {
|
||||
if (socketClientGlobal != nullptr) {
|
||||
socketClientGlobal->onreceiveTCPMessageEventDelegate.Broadcast(mainMessage, byteDataArray, clientConnectionIDGlobal);
|
||||
}
|
||||
if (tcpClientGlobal != nullptr) {
|
||||
tcpClientGlobal->onreceiveTCPMessageEventDelegate.Broadcast(mainMessage, byteDataArray, clientConnectionIDGlobal);
|
||||
if (tcpClientGlobal->tcpConnectAsyncNode != nullptr) {
|
||||
tcpClientGlobal->tcpConnectAsyncNode->triggerMessageEvent(byteDataArray, clientConnectionIDGlobal,mainMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
mainMessage.Empty();
|
||||
}
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
// Copyright 2022 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#include "SocketClientTCPSendDataThead.h"
|
||||
|
||||
|
||||
FSocketClientTCPSendDataThead::FSocketClientTCPSendDataThead(USocketClientBPLibrary* socketClientLibP, USocketClientTCPClient* tcpClientP, FString clientConnectionIDP) :
|
||||
socketClientLib(socketClientLibP),
|
||||
tcpClient(tcpClientP),
|
||||
clientConnectionID(clientConnectionIDP) {
|
||||
FString threadName = "FSendDataToServerThread" + FGuid::NewGuid().ToString();
|
||||
thread = FRunnableThread::Create(this, *threadName, 0, EThreadPriority::TPri_Normal);
|
||||
}
|
||||
|
||||
FSocketClientTCPSendDataThead::~FSocketClientTCPSendDataThead() {
|
||||
delete thread;
|
||||
}
|
||||
|
||||
uint32 FSocketClientTCPSendDataThead::Run(){
|
||||
|
||||
if (tcpClient == nullptr) {
|
||||
UE_LOG(LogTemp, Error, TEXT("Class is not initialized."));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*if (GEngine)
|
||||
GEngine->AddOnScreenDebugMessage(-1, 20.0f, FColor::Green, TEXT("tcp socket 1"));*/
|
||||
|
||||
FString clientConnectionIDGlobal = clientConnectionID;
|
||||
USocketClientBPLibrary* socketClientLibGlobal = socketClientLib;
|
||||
|
||||
//message wrapping
|
||||
FString stringSeparator = FString();
|
||||
uint8 byteSeparator = 0x00;
|
||||
ESocketClientTCPSeparator messageWrapping = ESocketClientTCPSeparator::E_None;
|
||||
tcpClient->getTcpSeparator(stringSeparator, byteSeparator, messageWrapping);
|
||||
|
||||
TArray<TCHAR> stringSeparatorArray = stringSeparator.GetCharArray();
|
||||
if (stringSeparatorArray.Num() > 0 && stringSeparatorArray.Last() == 0x00) {
|
||||
stringSeparatorArray.RemoveAt(stringSeparatorArray.Num() - 1, 1, true);
|
||||
}
|
||||
|
||||
if (messageWrapping == ESocketClientTCPSeparator::E_LengthSeparator && stringSeparatorArray.Num() == 0) {
|
||||
messageWrapping = ESocketClientTCPSeparator::E_None;
|
||||
UE_LOG(LogTemp, Warning, TEXT("Socket Client Plugin: Separator mode is set to String but there is no String Separator. Mode changed to none."));
|
||||
}
|
||||
|
||||
// get the socket
|
||||
FSocket* socket = tcpClient->getSocket();
|
||||
int32 sent = 0;
|
||||
|
||||
while (tcpClient->isRun()) {
|
||||
|
||||
// try to connect to the server
|
||||
if (socket == NULL || socket == nullptr) {
|
||||
UE_LOG(LogTemp, Error, TEXT("Connection not exist."));
|
||||
//AsyncTask(ENamedThreads::GameThread, [clientConnectionIDGlobal, socketClientLibGlobal]() {
|
||||
// if (socketClientLibGlobal != nullptr) {
|
||||
// socketClientLibGlobal->onsocketClientTCPConnectionEventDelegate.Broadcast(false, "Connection not exist:" + clientConnectionIDGlobal, clientConnectionIDGlobal);
|
||||
// socketClientLibGlobal->closeSocketClientConnection();
|
||||
// }
|
||||
//});
|
||||
break;
|
||||
}
|
||||
|
||||
if (socket != nullptr && tcpClient->isRun()) {
|
||||
|
||||
while (messageQueue.IsEmpty() == false) {
|
||||
FString m;
|
||||
messageQueue.Dequeue(m);
|
||||
FTCHARToUTF8 Convert(*m);
|
||||
sent = 0;
|
||||
|
||||
TArray<uint8> byteCache;
|
||||
|
||||
switch (messageWrapping)
|
||||
{
|
||||
case ESocketClientTCPSeparator::E_None:
|
||||
byteCache.Append((uint8*)Convert.Get(), Convert.Length());
|
||||
break;
|
||||
case ESocketClientTCPSeparator::E_ByteSeparator:
|
||||
byteCache.Append((uint8*)Convert.Get(), Convert.Length());
|
||||
byteCache.Add(byteSeparator);
|
||||
break;
|
||||
case ESocketClientTCPSeparator::E_StringSeparator:
|
||||
{
|
||||
m += stringSeparator;
|
||||
FTCHARToUTF8 ConvertWithSeparator(*m);
|
||||
byteCache.Append((uint8*)ConvertWithSeparator.Get(), ConvertWithSeparator.Length());
|
||||
}
|
||||
break;
|
||||
case ESocketClientTCPSeparator::E_LengthSeparator:
|
||||
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());
|
||||
break;
|
||||
}
|
||||
|
||||
socket->Send(byteCache.GetData(), byteCache.Num(), sent);
|
||||
}
|
||||
|
||||
while (byteArrayQueue.IsEmpty() == false) {
|
||||
|
||||
TArray<uint8> byteCache;
|
||||
byteArrayQueue.Dequeue(byteCache);
|
||||
sent = 0;
|
||||
|
||||
switch (messageWrapping)
|
||||
{
|
||||
case ESocketClientTCPSeparator::E_ByteSeparator:
|
||||
byteCache.Add(byteSeparator);
|
||||
break;
|
||||
case ESocketClientTCPSeparator::E_StringSeparator:
|
||||
{
|
||||
FTCHARToUTF8 ConvertWithSeparator(*stringSeparator);
|
||||
byteCache.Append((uint8*)ConvertWithSeparator.Get(), ConvertWithSeparator.Length());
|
||||
}
|
||||
break;
|
||||
case ESocketClientTCPSeparator::E_LengthSeparator:
|
||||
byteCache.InsertZeroed(0, 5);
|
||||
if (FGenericPlatformProperties::IsLittleEndian() == false) {
|
||||
uint8 a = 0x01;
|
||||
FMemory::Memcpy(byteCache.GetData(), &a, 1);
|
||||
}
|
||||
int32 dataLength = byteCache.Num() - 5;
|
||||
FMemory::Memcpy(byteCache.GetData() + 1, &dataLength, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
socket->Send(byteCache.GetData(), byteCache.Num(), sent);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (tcpClient->isRun()) {
|
||||
pauseThread(true);
|
||||
//workaround. suspend do not work on all platforms. lets sleep
|
||||
while (paused && tcpClient->isRun()) {
|
||||
FPlatformProcess::Sleep(0.01);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void FSocketClientTCPSendDataThead::sendMessage(FString messageP, TArray<uint8> byteArrayP) {
|
||||
if (messageP.Len() > 0)
|
||||
messageQueue.Enqueue(messageP);
|
||||
if (byteArrayP.Num() > 0)
|
||||
byteArrayQueue.Enqueue(byteArrayP);
|
||||
pauseThread(false);
|
||||
}
|
||||
|
||||
|
||||
void FSocketClientTCPSendDataThead::pauseThread(bool pause) {
|
||||
paused = pause;
|
||||
if (thread != nullptr)
|
||||
thread->Suspend(pause);
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#include "SocketClientUDP.h"
|
||||
|
||||
|
||||
USocketClientUDP::USocketClientUDP(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {
|
||||
this->AddToRoot();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void USocketClientUDP::socketClientUDPConnectionEventDelegate(const bool success, const FString message, const FString clientConnectionIDP){}
|
||||
void USocketClientUDP::receiveUDPMessageEventDelegate(const FString message, const TArray<uint8>& byteArray, const FString IPP, const int32 portP, const FString clientConnectionIDP) {}
|
||||
|
||||
void USocketClientUDP::init(USocketClientBPLibrary* socketClientLibP, UUDPInitAsyncNode* udpInitAsyncNodeP, FString domainOrIPP,
|
||||
ESocketClientIPType ipType, int32 portP, EReceiveFilterClient receiveFilterP, FString connectionIDP,
|
||||
int32 maxPacketSizeP) {
|
||||
socketClientBPLibrary = socketClientLibP;
|
||||
receiveFilter = receiveFilterP;
|
||||
connectionID = connectionIDP;
|
||||
domainOrIP = domainOrIPP;
|
||||
port = portP;
|
||||
udpInitAsyncNode = udpInitAsyncNodeP;
|
||||
|
||||
maxPacketSize = maxPacketSizeP;
|
||||
if (maxPacketSize < 1 || maxPacketSize > 65507)
|
||||
maxPacketSize = 65507;
|
||||
|
||||
UDPThread = new FSocketClientUDPReceiveDataThread(this, socketClientLibP, domainOrIPP, portP, ipType);
|
||||
}
|
||||
|
||||
|
||||
void USocketClientUDP::sendUDPMessage(FString domainOrIPP, ESocketClientIPType ipType, int32 portP, FString message, TArray<uint8> byteArray){
|
||||
if (UDPSendThread != nullptr) {
|
||||
UDPSendThread->addData(message, byteArray, domainOrIPP, portP, ipType);
|
||||
}
|
||||
}
|
||||
|
||||
void USocketClientUDP::closeUDPConnection() {
|
||||
|
||||
if (udpSocketReceiver != nullptr) {
|
||||
udpSocketReceiver->Stop();
|
||||
}
|
||||
|
||||
setRun(false);
|
||||
if (UDPSendThread != nullptr) {
|
||||
UDPSendThread->pauseThread(false);
|
||||
}
|
||||
|
||||
if (socketClientBPLibrary != nullptr) {
|
||||
FSocketClientPluginSession connectionSession = FSocketClientPluginSession();
|
||||
connectionSession.udpSocketReceiver = udpSocketReceiver;
|
||||
connectionSession.udpSendDataThead = UDPSendThread;
|
||||
connectionSession.udpReceiveDataThread = UDPThread;
|
||||
connectionSession.socket = socket;
|
||||
connectionSession.clientID = connectionID;
|
||||
socketClientBPLibrary->cleanConnection(connectionSession);
|
||||
}
|
||||
|
||||
//udpInitAsyncNode = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void USocketClientUDP::UDPReceiver(const FArrayReaderPtr& ArrayReaderPtr, const FIPv4Endpoint& EndPt) {
|
||||
|
||||
if (FSocketClientModule::isShuttingDown)
|
||||
return;
|
||||
|
||||
TSharedPtr<FInternetAddr> peerAddr = EndPt.ToInternetAddr();
|
||||
FString ipGlobal = peerAddr->ToString(false);
|
||||
int32 portGlobal = peerAddr->GetPort();
|
||||
|
||||
TArray<uint8> byteArray;
|
||||
if (receiveFilter == EReceiveFilterClient::E_SAB || receiveFilter == EReceiveFilterClient::E_B) {
|
||||
byteArray.Append(ArrayReaderPtr->GetData(), ArrayReaderPtr->Num());
|
||||
}
|
||||
|
||||
FString recvMessage;
|
||||
if (receiveFilter == EReceiveFilterClient::E_SAB || receiveFilter == EReceiveFilterClient::E_S) {
|
||||
ArrayReaderPtr->Add(0x00);// null-terminator
|
||||
char* Data = (char*)ArrayReaderPtr->GetData();
|
||||
recvMessage = FString(UTF8_TO_TCHAR(Data));
|
||||
}
|
||||
|
||||
//switch to gamethread
|
||||
USocketClientBPLibrary* socketClientBPLibraryGlobal = socketClientBPLibrary;
|
||||
USocketClientUDP* udpClientGlobal = this;
|
||||
FString clientConnectionIDGlobal = connectionID;
|
||||
UUDPInitAsyncNode* udpInitAsyncNodeGlobal = udpInitAsyncNode;
|
||||
AsyncTask(ENamedThreads::GameThread, [udpInitAsyncNodeGlobal, udpClientGlobal, recvMessage, byteArray, ipGlobal, portGlobal, socketClientBPLibraryGlobal, clientConnectionIDGlobal]() {
|
||||
if (FSocketClientModule::isShuttingDown)
|
||||
return;
|
||||
socketClientBPLibraryGlobal->onreceiveUDPMessageEventDelegate.Broadcast(recvMessage, byteArray, ipGlobal, portGlobal, clientConnectionIDGlobal);
|
||||
udpClientGlobal->onreceiveUDPMessageEventDelegate.Broadcast(recvMessage, byteArray, ipGlobal, portGlobal, clientConnectionIDGlobal);
|
||||
if (udpInitAsyncNodeGlobal != nullptr) {
|
||||
udpInitAsyncNodeGlobal->triggerMessageEvent(byteArray, clientConnectionIDGlobal, recvMessage, ipGlobal, portGlobal);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool USocketClientUDP::isRun(){
|
||||
return run;
|
||||
}
|
||||
|
||||
void USocketClientUDP::setRun(bool runP){
|
||||
run = runP;
|
||||
}
|
||||
|
||||
FSocket* USocketClientUDP::getSocket(){
|
||||
return socket;
|
||||
}
|
||||
|
||||
void USocketClientUDP::setSocket(FSocket* socketP){
|
||||
socket = socketP;
|
||||
}
|
||||
|
||||
void USocketClientUDP::setUDPSocketReceiver(FUdpSocketReceiver* udpSocketReceiverP){
|
||||
udpSocketReceiver = udpSocketReceiverP;
|
||||
}
|
||||
|
||||
FString USocketClientUDP::getIP(){
|
||||
return domainOrIP;
|
||||
}
|
||||
|
||||
void USocketClientUDP::setIP(FString ipP){
|
||||
domainOrIP = ipP;
|
||||
}
|
||||
|
||||
int32 USocketClientUDP::getPort(){
|
||||
return port;
|
||||
}
|
||||
|
||||
FString USocketClientUDP::getDomainOrIP(){
|
||||
return domainOrIP;
|
||||
}
|
||||
|
||||
FString USocketClientUDP::getConnectionID(){
|
||||
return connectionID;
|
||||
}
|
||||
|
||||
void USocketClientUDP::setUDPSendThread(FSocketClientUDPSendDataThead* udpSendThreadP){
|
||||
UDPSendThread = udpSendThreadP;
|
||||
}
|
||||
|
||||
int32 USocketClientUDP::getMaxPacketSize()
|
||||
{
|
||||
return maxPacketSize;
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
// Copyright 2022 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#include "SocketClientUDPReceiveDataThread.h"
|
||||
|
||||
|
||||
FSocketClientUDPReceiveDataThread::FSocketClientUDPReceiveDataThread(USocketClientUDP* udpClientP, USocketClientBPLibrary* socketClientP, FString ipP, int32 portP, ESocketClientIPType ipTypeP) :
|
||||
udpClient(udpClientP),
|
||||
socketClient(socketClientP),
|
||||
ipGlobal(ipP),
|
||||
portGlobal(portP),
|
||||
ipType(ipTypeP) {
|
||||
FString threadName = "FServerUDPConnectionThread_" + FGuid::NewGuid().ToString();
|
||||
thread = FRunnableThread::Create(this, *threadName, 0, EThreadPriority::TPri_Normal);
|
||||
}
|
||||
|
||||
FSocketClientUDPReceiveDataThread::~FSocketClientUDPReceiveDataThread() {
|
||||
if (udpClient != nullptr && udpClient->udpInitAsyncNode != nullptr) {
|
||||
udpClient->udpInitAsyncNode = nullptr;
|
||||
}
|
||||
delete thread;
|
||||
}
|
||||
|
||||
void FSocketClientUDPReceiveDataThread::triggerInitEvent(bool success, USocketClientUDP* udpClientP, USocketClientBPLibrary* socketClientP,
|
||||
FString serverMessage, FString connectionID){
|
||||
AsyncTask(ENamedThreads::GameThread, [success, udpClientP, socketClientP, serverMessage, connectionID]() {
|
||||
if (socketClientP != nullptr)
|
||||
socketClientP->onsocketClientUDPConnectionEventDelegate.Broadcast(success, serverMessage, connectionID);
|
||||
if (udpClientP != nullptr) {
|
||||
udpClientP->onsocketClientUDPConnectionEventDelegate.Broadcast(success, serverMessage, connectionID);
|
||||
if (udpClientP->udpInitAsyncNode != nullptr) {
|
||||
udpClientP->udpInitAsyncNode->triggerInitEvent(success, connectionID, serverMessage);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
uint32 FSocketClientUDPReceiveDataThread::Run() {
|
||||
|
||||
USocketClientUDP* udpClientGlobal = udpClient;
|
||||
FString ip = socketClient->resolveDomain(ipGlobal, ipType);
|
||||
udpClient->setIP(ip);
|
||||
int32 port = portGlobal;
|
||||
FString connectionID = udpClient->getConnectionID();
|
||||
|
||||
|
||||
if (socket == nullptr || socket == NULL) {
|
||||
|
||||
FString endpointAdress = ip + ":" + FString::FromInt(port);
|
||||
FIPv4Endpoint Endpoint;
|
||||
|
||||
// create the socket
|
||||
FString socketName;
|
||||
ISocketSubsystem* socketSubsystem = USocketClientBPLibrary::getSocketSubSystem();
|
||||
|
||||
TSharedPtr<class FInternetAddr> addr = socketSubsystem->CreateInternetAddr();
|
||||
bool validIP = true;
|
||||
addr->SetPort(port);
|
||||
addr->SetIp(*ip, validIP);
|
||||
|
||||
|
||||
if (!validIP) {
|
||||
UE_LOG(LogTemp, Error, TEXT("SocketClient UDP. Can't set ip"));
|
||||
triggerInitEvent(false, udpClient, socketClient, "SocketClient UDP. Can't set ip", connectionID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
socket = socketSubsystem->CreateSocket(NAME_DGram, *socketName, addr->GetProtocolType());
|
||||
|
||||
|
||||
if (socket == nullptr || socket == NULL) {
|
||||
const TCHAR* SocketErr = socketSubsystem->GetSocketError(SE_GET_LAST_ERROR_CODE);
|
||||
UE_LOG(LogTemp, Error, TEXT("UE could not init a UDP socket. You can only create listening connections on local IPs. An external IP must be redirected to a local IP in your router. %s:%i. Error: %s"), *ip, port, SocketErr);
|
||||
triggerInitEvent(false, udpClient, socketClient, "(Error 0) UE could not init a UDP socket. You can only create listening connections on local IPs. An external IP must be redirected to a local IP in your router." + addr->ToString(true) + " Error:" + SocketErr, connectionID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!socket->SetRecvErr()) {
|
||||
UE_LOG(LogTemp, Error, TEXT("SocketClient UDP. Can't set recverr"));
|
||||
}
|
||||
|
||||
|
||||
if (socket == nullptr || socket == NULL || !validIP) {
|
||||
const TCHAR* SocketErr = socketSubsystem->GetSocketError(SE_GET_LAST_ERROR_CODE);
|
||||
UE_LOG(LogTemp, Error, TEXT("UE could not init a UDP socket. You can only create listening connections on local IPs. An external IP must be redirected to a local IP in your router. %s:%i. Error: %s"), *ip, port, SocketErr);
|
||||
triggerInitEvent(false, udpClient, socketClient, "(Error 1) UE could not init a UDP socket. You can only create listening connections on local IPs. An external IP must be redirected to a local IP in your router." + addr->ToString(true) + " Error:" + SocketErr, connectionID);
|
||||
return 0;
|
||||
}
|
||||
socket->SetReuseAddr(true);
|
||||
socket->SetNonBlocking(true);
|
||||
socket->SetBroadcast(true);
|
||||
|
||||
if (!socket->Bind(*addr)) {
|
||||
const TCHAR* SocketErr = socketSubsystem->GetSocketError(SE_GET_LAST_ERROR_CODE);
|
||||
UE_LOG(LogTemp, Error, TEXT("UE could not init a UDP socket. You can only create listening connections on local IPs. An external IP must be redirected to a local IP in your router. %s:%i. Error: %s"), *ip, port, SocketErr);
|
||||
triggerInitEvent(false, udpClient, socketClient, "(Error 2) UE could not init a UDP socket. You can only create listening connections on local IPs. An external IP must be redirected to a local IP in your router." + addr->ToString(true) + " Error:" + SocketErr, connectionID);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FTimespan ThreadWaitTime = FTimespan::FromMilliseconds(100);
|
||||
FUdpSocketReceiver* udpSocketReceiver = new FUdpSocketReceiver(socket, ThreadWaitTime, TEXT("SocketClientBPLibUDPReceiverThread"));
|
||||
udpSocketReceiver->OnDataReceived().BindUObject(udpClient, &USocketClientUDP::UDPReceiver);
|
||||
udpSocketReceiver->Start();
|
||||
udpClient->setUDPSocketReceiver(udpSocketReceiver);
|
||||
|
||||
udpClient->setSocket(socket);
|
||||
udpClient->setRun(true);
|
||||
udpClient->setUDPSendThread(new FSocketClientUDPSendDataThead(udpClient, socketClient, ip, port));
|
||||
|
||||
|
||||
triggerInitEvent(true, udpClient, socketClient, "Init UDP Connection OK. " + addr->ToString(true), connectionID);
|
||||
|
||||
}
|
||||
thread = nullptr;
|
||||
return 0;
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
// Copyright 2022 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#include "SocketClientUDPSendDataThead.h"
|
||||
|
||||
FSocketClientUDPSendDataThead::FSocketClientUDPSendDataThead(USocketClientUDP* udpClientP, USocketClientBPLibrary* socketClientP, FString mySocketipP, int32 mySocketportP) :
|
||||
udpClient(udpClientP),
|
||||
socketClient(socketClientP),
|
||||
mySocketip(mySocketipP),
|
||||
mySocketport(mySocketportP) {
|
||||
FString threadName = "FServerUDPSendMessageThread_" + FGuid::NewGuid().ToString();
|
||||
thread = FRunnableThread::Create(this, *threadName, 0, EThreadPriority::TPri_Normal);
|
||||
}
|
||||
|
||||
FSocketClientUDPSendDataThead::~FSocketClientUDPSendDataThead() {
|
||||
delete thread;
|
||||
}
|
||||
|
||||
uint32 FSocketClientUDPSendDataThead::Run() {
|
||||
|
||||
FSocket* socket = udpClient->getSocket();
|
||||
FString connectionID = udpClient->getConnectionID();
|
||||
maxPacketSize = udpClient->getMaxPacketSize();
|
||||
|
||||
while (udpClient->isRun() && socket != nullptr) {
|
||||
|
||||
|
||||
if (udpClient->isRun() && (messageQueue.IsEmpty() == false || byteArrayQueue.IsEmpty() == false)) {
|
||||
|
||||
int32 sent = 0;
|
||||
TArray<uint8> byteArray;
|
||||
if (validInternetAdress) {
|
||||
while (messageQueue.IsEmpty() == false) {
|
||||
FString m;
|
||||
messageQueue.Dequeue(m);
|
||||
FTCHARToUTF8 Convert(*m);
|
||||
byteArray.Append((uint8*)Convert.Get(), Convert.Length());
|
||||
sendBytes(socket, byteArray, sent, internetAdress);
|
||||
}
|
||||
|
||||
while (byteArrayQueue.IsEmpty() == false) {
|
||||
byteArrayQueue.Dequeue(byteArray);
|
||||
sendBytes(socket, byteArray, sent, internetAdress);
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
UE_LOG(LogTemp, Error, TEXT("Can't send to %s:%i . Adress not valid."), *sendToip, sendToport);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (udpClient->isRun()) {
|
||||
pauseThread(true);
|
||||
//workaround. suspend do not work on all platforms. lets sleep
|
||||
while (paused && udpClient->isRun()) {
|
||||
FPlatformProcess::Sleep(0.01);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (socket != nullptr) {
|
||||
socket->Close();
|
||||
socket = nullptr;
|
||||
udpClient->setSocket(nullptr);
|
||||
}
|
||||
|
||||
|
||||
USocketClientBPLibrary* socketClientTMP = socketClient;
|
||||
USocketClientUDP* udpClientGlobal = udpClient;
|
||||
FString ipGlobal = mySocketip;
|
||||
int32 portGlobal = mySocketport;
|
||||
AsyncTask(ENamedThreads::GameThread, [socketClientTMP, udpClientGlobal, ipGlobal, portGlobal, connectionID]() {
|
||||
if (socketClientTMP != nullptr)
|
||||
socketClientTMP->onsocketClientUDPConnectionEventDelegate.Broadcast(false, "UDP connection closed. " + ipGlobal + ":" + FString::FromInt(portGlobal), connectionID);
|
||||
if (udpClientGlobal != nullptr)
|
||||
udpClientGlobal->onsocketClientUDPConnectionEventDelegate.Broadcast(false, "UDP connection closed. " + ipGlobal + ":" + FString::FromInt(portGlobal), connectionID);
|
||||
});
|
||||
|
||||
|
||||
thread = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void FSocketClientUDPSendDataThead::addData(FString messageP, TArray<uint8> byteArrayP, FString domainOrIP, int32 port, ESocketClientIPType ipType) {
|
||||
|
||||
//new adress?
|
||||
if (sendToport != port || sendToDomainOrIP.Equals(domainOrIP) == false) {
|
||||
|
||||
sendToDomainOrIP = domainOrIP;
|
||||
sendToip = socketClient->resolveDomain(domainOrIP, ipType);
|
||||
sendToport = port;
|
||||
|
||||
internetAdress->SetIp(*sendToip, validInternetAdress);
|
||||
internetAdress->SetPort(sendToport);
|
||||
if (!validInternetAdress) {
|
||||
//don't send to many error messages. one second = 10000000 ticks
|
||||
if (((FDateTime::Now().GetTicks()) - lastErrorMessageTime) >= 10000000) {
|
||||
UE_LOG(LogTemp, Error, TEXT("Can't create Adress %s:%i"), *sendToip, sendToport);
|
||||
lastErrorMessageTime = FDateTime::Now().GetTicks();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!validInternetAdress) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (messageP.Len() > 0)
|
||||
messageQueue.Enqueue(messageP);
|
||||
if (byteArrayP.Num() > 0)
|
||||
byteArrayQueue.Enqueue(byteArrayP);
|
||||
pauseThread(false);
|
||||
|
||||
}
|
||||
|
||||
void FSocketClientUDPSendDataThead::pauseThread(bool pause) {
|
||||
paused = pause;
|
||||
if (thread != nullptr)
|
||||
thread->Suspend(pause);
|
||||
}
|
||||
|
||||
void FSocketClientUDPSendDataThead::sendBytes(FSocket*& socketP, TArray<uint8>& byteArray, int32& sent, TSharedRef<FInternetAddr>& addr) {
|
||||
if (byteArray.Num() > maxPacketSize) {
|
||||
TArray<uint8> byteArrayTemp;
|
||||
for (int32 i = 0; i < byteArray.Num(); i++) {
|
||||
byteArrayTemp.Add(byteArray[i]);
|
||||
if (byteArrayTemp.Num() == maxPacketSize) {
|
||||
sent = 0;
|
||||
socketP->SendTo(byteArrayTemp.GetData(), byteArrayTemp.Num(), sent, *addr);
|
||||
byteArrayTemp.Empty();
|
||||
}
|
||||
}
|
||||
if (byteArrayTemp.Num() > 0) {
|
||||
sent = 0;
|
||||
socketP->SendTo(byteArrayTemp.GetData(), byteArrayTemp.Num(), sent, *addr);
|
||||
byteArrayTemp.Empty();
|
||||
}
|
||||
}
|
||||
else {
|
||||
sent = 0;
|
||||
socketP->SendTo(byteArray.GetData(), byteArray.Num(), sent, *addr);
|
||||
}
|
||||
|
||||
byteArray.Empty();
|
||||
}
|
||||
Reference in New Issue
Block a user