增加多屏显示,视频播放
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"FileVersion": 3,
|
||||
"Version": 255,
|
||||
"VersionName": "2.55",
|
||||
"FriendlyName": "SimpleTCPUDPSocketClient",
|
||||
"Description": "TCP and UDP Blueprint Socket Client",
|
||||
"Category": "Sockets",
|
||||
"CreatedBy": "Socke",
|
||||
"CreatedByURL": "",
|
||||
"DocsURL": "http://virtualbird.de/ue4Doku/SimpleTCPUDPSocketClient2/",
|
||||
"MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/5d4ddd5493ce4d2295ef9be6c67eff82",
|
||||
"SupportURL": "mailto:unrealmarketplace@virtualbird.de",
|
||||
"EngineVersion": "5.3.0",
|
||||
"CanContainContent": false,
|
||||
"Installed": true,
|
||||
"Modules": [
|
||||
{
|
||||
"Name": "SocketClient",
|
||||
"Type": "Runtime",
|
||||
"LoadingPhase": "PreLoadingScreen",
|
||||
"PlatformAllowList": [
|
||||
"Win64",
|
||||
"Mac",
|
||||
"IOS",
|
||||
"Android",
|
||||
"Linux"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+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();
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
#include "DNSClientSocketClient.generated.h"
|
||||
|
||||
UCLASS()
|
||||
class SOCKETCLIENT_API UDNSClientSocketClient : public UObject
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
public:
|
||||
void resolveDomain(ISocketSubsystem* socketSubSystem, FString domain, bool useDNSCache = true, FString dnsIP = FString("8.8.8.8"));
|
||||
|
||||
void UDPReceiver(const FArrayReaderPtr& ArrayReaderPtr, const FIPv4Endpoint& EndPt);
|
||||
|
||||
FSocket* socket = nullptr;
|
||||
|
||||
bool isResloving();
|
||||
FString getIP();
|
||||
|
||||
private:
|
||||
bool resolving;
|
||||
FString ip;
|
||||
FString domain;
|
||||
TMap<FString, FString> dnsCache;
|
||||
};
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
#include "SocketClientBPLibrary.h"
|
||||
#include "FileFunctionsSocketClient.generated.h"
|
||||
|
||||
class FReadFileInPartsSocketClientThread;
|
||||
|
||||
|
||||
UCLASS(Blueprintable, BlueprintType)
|
||||
class SOCKETCLIENT_API UFileFunctionsSocketClient : public UObject
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UFUNCTION()
|
||||
static UFileFunctionsSocketClient* getFileFunctionsSocketClientTarget();
|
||||
static UFileFunctionsSocketClient* fileFunctionsSocketClient;
|
||||
|
||||
|
||||
|
||||
|
||||
static FString getCleanDirectory(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void writeBytesToFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, TArray<uint8> bytes, bool& success);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void addBytesToFileAndCloseIt(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, TArray<uint8> bytes, bool& success);
|
||||
//UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
// static void splittFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, int32 parts, bool& success);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static TArray<uint8> readBytesFromFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, bool &success);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void readStringFromFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, bool& success, FString& data);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void writeStringToFile(EFileFunctionsSocketClientDirectoryType directoryType, FString data, FString filePath, EFileFunctionsSocketClientEncodingOptions fileEncoding, bool& success);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void getMD5FromFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, bool& success, FString& MD5);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void getMD5FromFileAbsolutePath(FString filePath, bool& success, FString& MD5);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void stringToBase64String(FString string, FString& base64String);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void base64StringToString(FString& string, FString base64String);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void bytesToBase64String(TArray<uint8> bytes, FString& base64String);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static TArray<uint8> base64StringToBytes(FString base64String, bool& success);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void fileToBase64String(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, bool& success, FString& base64String, FString& fileName);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static bool fileExists(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static bool fileExistsAbsolutePath(FString filePath);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static bool directoryExists(EFileFunctionsSocketClientDirectoryType directoryType, FString path);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static int64 fileSize(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static int64 fileSizeAbsolutePath(FString filePath);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static bool deleteFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketServer|SpecialFunctions|File")
|
||||
static bool deleteFileAbsolutePath(FString filePath);
|
||||
/** Delete a directory and return true if the directory was deleted or otherwise does not exist. **/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static bool deleteDirectory(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
/** Return true if the file is read only. **/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static bool isReadOnly(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
/** Attempt to move a file. Return true if successful. Will not overwrite existing files. **/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static bool moveFile(EFileFunctionsSocketClientDirectoryType directoryTypeTo, FString filePathTo, EFileFunctionsSocketClientDirectoryType directoryTypeFrom, FString filePathFrom);
|
||||
/** Attempt to change the read only status of a file. Return true if successful. **/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static bool setReadOnly(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, bool bNewReadOnlyValue);
|
||||
/** Return the modification time of a file. Returns FDateTime::MinValue() on failure **/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static FDateTime getTimeStamp(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
/** Sets the modification time of a file **/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void setTimeStamp(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, FDateTime DateTime);
|
||||
/** Return the last access time of a file. Returns FDateTime::MinValue() on failure **/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static FDateTime getAccessTimeStamp(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
/** For case insensitive filesystems, returns the full path of the file with the same case as in the filesystem */
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static FString getFilenameOnDisk(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
/** Create a directory and return true if the directory was created or already existed. **/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static bool createDirectory(EFileFunctionsSocketClientDirectoryType directoryType, FString path);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void getAllFilesFromDirectory(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, int32& count, TArray<FString>& files, TArray<FString>& filePaths, FString fileType ="*.*");
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Encrypts an file with AES in 256bit
|
||||
* @param filePath The path must contain the file at the end.
|
||||
* @param newFileName New name for the encrypted file without path. It can also take the same name of the unencrypted file. But the file will be overwritten. Possible data loss.
|
||||
* @param keyIn256Bit The key must be a string with 32 characters. Please use ANSI characters only!
|
||||
* @param writeEncryptedFileSizeToFile To decrypt the file correctly the size of the original file is needed. With true the size is written as int64 (8 byte) at the beginning of the file.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|AES")
|
||||
static bool encryptFileWithAES(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, FString newFileName, FString keyIn256Bit, bool writeEncryptedFileSizeToFile = true);
|
||||
|
||||
/**
|
||||
* Decrypts an file that has been encrypted in AES with 256bit
|
||||
* @param filePath The path must contain the file at the end.
|
||||
* @param newFileName New name for the decrypted file without path. It can also take the same name of the dencrypted file. But the file will be overwritten. Possible data loss.
|
||||
* @param keyIn256Bit The key must be a string with 32 characters. Please use ANSI characters only!
|
||||
* @param hasEncryptedFileSizeInFile To decrypt the file correctly the size of the original file is needed. With true the size is read from the first 8 bytes in the file.
|
||||
* @param originalFileSize To decrypt the file correctly the size of the original file is needed. If the size of the original file is not in the first bytes of the file, you must specify it here.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|AES")
|
||||
static bool decryptFileWithAES(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, FString newFileName, FString keyIn256Bit, bool hasEncryptedFileSizeInFile = true, int64 originalFileSize = 0);
|
||||
|
||||
/**
|
||||
* Encrypts a string with AES in 256bit and returns the encrypted string as Base64 string.
|
||||
* @param message The string to be encrypted
|
||||
* @param keyIn256Bit The key must be a string with 32 characters. Please use ANSI characters only!
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|AES")
|
||||
static FString encryptMessageWithAES(FString message, FString keyIn256Bit);
|
||||
|
||||
/**
|
||||
* Decrypts a Base64 string that has been encrypted in AES with 256bit and returns the string.
|
||||
* @param message The string to be decrypted
|
||||
* @param keyIn256Bit The key must be a string with 32 characters. Please use ANSI characters only!
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|AES")
|
||||
static FString decryptMessageWithAES(FString encryptedBase64Message, FString keyIn256Bit);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|String")
|
||||
static FString int64ToString(int64 num);
|
||||
|
||||
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static struct FFileFunctionsSocketClientOpenFile openFile(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static int64 addBytesToFile(struct FFileFunctionsSocketClientOpenFile openFile, TArray<uint8>bytes);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void closeFile(struct FFileFunctionsSocketClientOpenFile openFile);
|
||||
|
||||
/**
|
||||
* With this function you can read a file piece by piece. This reduces the RAM consumption to almost zero and files can be read in infinite size.
|
||||
*@param bufferSize In bytes. This is the size of the file pieces that are being read.
|
||||
*@param delayBetweenReadsInSeconds Specified in seconds. The higher the value, the slower the file is read (0.0001 minimum). When sending data over the network/internet, please make sure not to send data too fast. SSDs can read data much faster than you can send it over a network. This means that the data ends up in some buffers (RAM) and can also cause them to overflow.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File", meta = (AdvancedDisplay = 2))
|
||||
static void readBytesFromFileInPartsAsync(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, int32 bufferSize = 65536, float delayBetweenReadsInSeconds = 0.01f);
|
||||
void readBytesFromFileInPartsAsyncInternal(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, int32 bufferSize = 65536, float delayBetweenReadsInSeconds = 0.01f);
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
static void cancelReadBytesFromFileInParts(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
void cancelReadBytesFromFileInPartsInternal(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath);
|
||||
void cleanReadBytesFromFileInParts(FString cleanDir);
|
||||
//UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|File")
|
||||
// static void changeDelayInBytesFromFileInParts(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, float delayBetweenReadsInSeconds = 0.1f);
|
||||
//void changeDelayInBytesFromFileInPartsInternal(EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, float delayBetweenReadsInSeconds = 0.1f);
|
||||
|
||||
|
||||
TMap<FString, FReadFileInPartsSocketClientThread*> readFileInPartsThreads;
|
||||
|
||||
private:
|
||||
static TArray<uint8> FStringToByteArray(FString s);
|
||||
|
||||
|
||||
};
|
||||
|
||||
/* asynchronous Thread*/
|
||||
class SOCKETCLIENT_API FReadFileInPartsSocketClientThread : public FRunnable {
|
||||
|
||||
public:
|
||||
|
||||
FReadFileInPartsSocketClientThread(FString cleanDirP, int32 bufferSizeP, float delayBetweenReadsInSecondsP) :
|
||||
cleanDir(cleanDirP),
|
||||
bufferSize(bufferSizeP),
|
||||
delayBetweenReadsInSeconds(delayBetweenReadsInSecondsP)
|
||||
{
|
||||
FString threadName = "FReadFileInPartsSocketClientThread" + FGuid::NewGuid().ToString();
|
||||
thread = FRunnableThread::Create(this, *threadName, 0, EThreadPriority::TPri_Normal);
|
||||
}
|
||||
|
||||
virtual uint32 Run() override {
|
||||
|
||||
FArchive* reader = IFileManager::Get().CreateFileReader(*cleanDir);
|
||||
if (reader == nullptr || reader->TotalSize() == 0) {
|
||||
AsyncTask(ENamedThreads::GameThread, []() {
|
||||
USocketClientBPLibrary::getSocketClientTarget()->onreadBytesFromFileInPartsEventDelegate.Broadcast(0, 0, true, TArray<uint8>());
|
||||
});
|
||||
if (reader != nullptr) {
|
||||
reader->Close();
|
||||
}
|
||||
delete reader;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (delayBetweenReadsInSeconds <= 0) {
|
||||
delayBetweenReadsInSeconds = 0.0001f;
|
||||
}
|
||||
|
||||
int64 fileSize = reader->TotalSize();
|
||||
int64 readSize = 0;
|
||||
int64 lastPosition = 0;
|
||||
TArray<uint8> buffer;
|
||||
|
||||
if (bufferSize > fileSize) {
|
||||
bufferSize = fileSize;
|
||||
}
|
||||
|
||||
while (run && 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("xxxxx READ: %i"), buffer.Num());
|
||||
|
||||
|
||||
AsyncTask(ENamedThreads::GameThread, [fileSize, lastPosition, buffer]() {
|
||||
USocketClientBPLibrary::getSocketClientTarget()->onreadBytesFromFileInPartsEventDelegate.Broadcast(fileSize, lastPosition, false, buffer);
|
||||
});
|
||||
|
||||
FPlatformProcess::Sleep(delayBetweenReadsInSeconds);
|
||||
|
||||
}
|
||||
|
||||
AsyncTask(ENamedThreads::GameThread, [fileSize, lastPosition]() {
|
||||
USocketClientBPLibrary::getSocketClientTarget()->onreadBytesFromFileInPartsEventDelegate.Broadcast(fileSize, lastPosition, true, TArray<uint8>());
|
||||
});
|
||||
|
||||
UFileFunctionsSocketClient::getFileFunctionsSocketClientTarget()->cleanReadBytesFromFileInParts(cleanDir);
|
||||
//buffer.Empty();
|
||||
if (reader != nullptr) {
|
||||
reader->Close();
|
||||
}
|
||||
delete reader;
|
||||
thread = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void stopThread() {
|
||||
run = false;
|
||||
}
|
||||
|
||||
void setDelayBetweenReadsInSeconds(float d) {
|
||||
delayBetweenReadsInSeconds = d;
|
||||
if (delayBetweenReadsInSeconds <= 0) {
|
||||
delayBetweenReadsInSeconds = 0.001f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
bool run = true;
|
||||
FString cleanDir;
|
||||
int32 bufferSize;
|
||||
float delayBetweenReadsInSeconds;
|
||||
//USocketClientBPLibrary* mainLib = USocketClientBPLibrary::getSocketClientTarget();
|
||||
|
||||
FRunnableThread* thread = nullptr;
|
||||
};
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Sockets.h"
|
||||
#include "SocketSubsystem.h"
|
||||
#include "Interfaces/IPv4/IPv4Endpoint.h"
|
||||
#include "Common/UdpSocketReceiver.h"
|
||||
#include "Common/UdpSocketBuilder.h"
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "Engine/LocalPlayer.h"
|
||||
#include "Kismet/BlueprintFunctionLibrary.h"
|
||||
#include "Kismet/BlueprintAsyncActionBase.h"
|
||||
#include "Async/Async.h"
|
||||
#include "HAL/PlatformFileManager.h"
|
||||
#include "HAL/FileManager.h"
|
||||
#include "Containers/Queue.h"
|
||||
#include "Misc/FileHelper.h"
|
||||
#include "Misc/Paths.h"
|
||||
#include "Misc/Base64.h"
|
||||
#include "Misc/SecureHash.h"
|
||||
#include "Misc/AES.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
#include "Runtime/Launch/Resources/Version.h"
|
||||
#if ENGINE_MAJOR_VERSION == 5 & ENGINE_MINOR_VERSION >= 2
|
||||
#include "IPAddressAsyncResolve.h"
|
||||
#endif
|
||||
#include "SocketClient.generated.h"
|
||||
|
||||
|
||||
class FSocketClientTCPReceiveDataThread;
|
||||
class FSocketClientTCPSendDataThead;
|
||||
|
||||
class FSocketClientTCPFileHandlerThread;
|
||||
|
||||
class FUdpSocketReceiver;
|
||||
class FSocketClientUDPReceiveDataThread;
|
||||
class FSocketClientUDPSendDataThead;
|
||||
|
||||
class UTCPConnectAsyncNode;
|
||||
class UUDPInitAsyncNode;
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FFileFunctionsSocketClientOpenFile
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
FArchive* writer = nullptr;
|
||||
|
||||
};
|
||||
|
||||
USTRUCT()
|
||||
struct FSocketClientPluginSession
|
||||
{
|
||||
GENERATED_USTRUCT_BODY()
|
||||
|
||||
int64 addToCleanerTime = 0;
|
||||
FString clientID = FString();
|
||||
FSocket* socket = nullptr;
|
||||
|
||||
FSocketClientTCPSendDataThead* tcpSendThread = nullptr;
|
||||
FSocketClientTCPReceiveDataThread* tcpRecieverThread = nullptr;
|
||||
|
||||
FSocketClientTCPFileHandlerThread* tcpFileHandlerThread = nullptr;
|
||||
|
||||
FUdpSocketReceiver* udpSocketReceiver = nullptr;
|
||||
FSocketClientUDPSendDataThead* udpSendDataThead = nullptr;
|
||||
FSocketClientUDPReceiveDataThread* udpReceiveDataThread = nullptr;
|
||||
|
||||
};
|
||||
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EFileFunctionsSocketClientDirectoryType : uint8
|
||||
{
|
||||
E_gd UMETA(DisplayName = "Game directory"),
|
||||
E_ad UMETA(DisplayName = "Absolute directory")
|
||||
};
|
||||
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EFileFunctionsSocketClientEncodingOptions : uint8
|
||||
{
|
||||
E_AutoDetect UMETA(DisplayName = "AutoDetect"),
|
||||
E_ForceAnsi UMETA(DisplayName = "ForceAnsi"),
|
||||
E_ForceUnicode UMETA(DisplayName = "ForceUnicode"),
|
||||
E_ForceUTF8 UMETA(DisplayName = "ForceUTF8"),
|
||||
E_ForceUTF8WithoutBOM UMETA(DisplayName = "ForceUTF8WithoutBOM")
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class EReceiveFilterClient : uint8
|
||||
{
|
||||
E_SAB UMETA(DisplayName = "Message And Bytes"),
|
||||
E_S UMETA(DisplayName = "Message"),
|
||||
E_B UMETA(DisplayName = "Bytes")
|
||||
|
||||
};
|
||||
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ESocketPlatformClient : uint8
|
||||
{
|
||||
E_SSC_SYSTEM UMETA(DisplayName = "System"),
|
||||
E_SSC_DEFAULT UMETA(DisplayName = "Auto"),
|
||||
E_SSC_WINDOWS UMETA(DisplayName = "WINDOWS"),
|
||||
E_SSC_MAC UMETA(DisplayName = "MAC"),
|
||||
E_SSC_IOS UMETA(DisplayName = "IOS"),
|
||||
E_SSC_UNIX UMETA(DisplayName = "UNIX"),
|
||||
E_SSC_ANDROID UMETA(DisplayName = "ANDROID"),
|
||||
E_SSC_PS4 UMETA(DisplayName = "PS4"),
|
||||
E_SSC_XBOXONE UMETA(DisplayName = "XBOXONE"),
|
||||
E_SSC_HTML5 UMETA(DisplayName = "HTML5"),
|
||||
E_SSC_SWITCH UMETA(DisplayName = "SWITCH")
|
||||
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ESocketClientIPType : uint8
|
||||
{
|
||||
E_ipv4 UMETA(DisplayName = "IPv4"),
|
||||
E_ipv6 UMETA(DisplayName = "IPv6")
|
||||
};
|
||||
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ESocketClientTCPSeparator : uint8
|
||||
{
|
||||
E_None UMETA(DisplayName = "None"),
|
||||
E_ByteSeparator UMETA(DisplayName = "Separate via one Byte"),
|
||||
E_StringSeparator UMETA(DisplayName = "Separate via String"),
|
||||
E_LengthSeparator UMETA(DisplayName = "Separate by Length")
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef __FileFunctionsSocketClient
|
||||
#define __FileFunctionsSocketClient
|
||||
#include "FileFunctionsSocketClient.h"
|
||||
#endif
|
||||
|
||||
#ifndef __SocketClientCleanerThread
|
||||
#define __SocketClientCleanerThread
|
||||
#include "SocketClientCleanerThread.h"
|
||||
#endif
|
||||
|
||||
#ifndef __SocketClientAsyncNodes
|
||||
#define __SocketClientAsyncNodes
|
||||
#include "SocketClientAsyncNodes.h"
|
||||
#endif
|
||||
|
||||
#ifndef __SocketClientBPLibrary
|
||||
#define __SocketClientBPLibrary
|
||||
#include "SocketClientBPLibrary.h"
|
||||
#endif
|
||||
|
||||
#ifndef __SocketClientTCP
|
||||
#define __SocketClientTCP
|
||||
#include "SocketClientTCP.h"
|
||||
#endif
|
||||
|
||||
#ifndef __SocketClientUDP
|
||||
#define __SocketClientUDP
|
||||
#include "SocketClientUDP.h"
|
||||
#endif
|
||||
|
||||
class FSocketClientModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
|
||||
static bool isShuttingDown;
|
||||
};
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
// Copyright 2022 David Romanski(Socke). All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
|
||||
#ifndef __SocketClientBPLibrary
|
||||
#define __SocketClientBPLibrary
|
||||
#include "SocketClientBPLibrary.h"
|
||||
#endif
|
||||
|
||||
#include "SocketClientAsyncNodes.generated.h"
|
||||
|
||||
|
||||
/*--- TCP -------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
UCLASS()
|
||||
class SOCKETCLIENT_API UTCPConnectAsyncNode : public UBlueprintAsyncActionBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FTCPConnectDelegate, const FString, connenctionInfo, const FString, clientConnectionID,
|
||||
const FString, messageFromServer, const TArray<uint8>&, byteArrayFromServer);
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FTCPConnectDelegate OnConnect;
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FTCPConnectDelegate OnDisconnect;
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FTCPConnectDelegate OnServerMessage;
|
||||
|
||||
/**
|
||||
* Connect to a TCP Server
|
||||
* @param domainOrIP IP or Domain of your server
|
||||
* @param ipType
|
||||
* @param port
|
||||
* @param receiveFilter This allows you to decide which data type you want to receive. If you receive files it makes no sense to convert them into a string.
|
||||
* @param messageWrapping It may be that data packets are split or merged when transmitted over TCP in order to optimize the transmission. For example, if you send "Hello" two times in a row very quickly, it can happen that "HelloHa" and "llo" arrive. To counteract this circumstance there are options to separate the data packets.
|
||||
* @param optionalCustomConnectionID Instead of an automatically generated ConnectionID you can use your own ID with this parameter.
|
||||
* @param disableNaglesAlgorithm Don't change it if you don't know what this option is for! With this you can disable the TCP Nagle's algorithm to send (in LAN) very small data packets faster.
|
||||
**/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|TCP", meta = (BlueprintInternalUseOnly = "true", AdvancedDisplay = 6))
|
||||
static UTCPConnectAsyncNode* socketClientTCPConnectionAsyncNode(FString domainOrIP, ESocketClientIPType ipType, int32 port, EReceiveFilterClient receiveFilters,
|
||||
ESocketClientTCPSeparator messageWrapping, FString optionalCustomConnectionID, bool disableNaglesAlgorithm = false);
|
||||
|
||||
|
||||
virtual void Activate() override;
|
||||
|
||||
void triggerConnectionEvent(bool success, FString clientConnectionID, FString serverMessage);
|
||||
void triggerMessageEvent(TArray<uint8> byteDataArray, FString clientConnectionID, FString serverMessage);
|
||||
|
||||
private:
|
||||
UTCPConnectAsyncNode* instance = nullptr;
|
||||
FString domainOrIP = "0.0.0.0";
|
||||
ESocketClientIPType ipType = ESocketClientIPType::E_ipv4;
|
||||
int32 port = 9999;
|
||||
EReceiveFilterClient receiveFilters = EReceiveFilterClient::E_SAB;
|
||||
ESocketClientTCPSeparator messageWrapping = ESocketClientTCPSeparator::E_None;
|
||||
FString optionalCustomConnectionID = FString();
|
||||
FString connectionID = FString();
|
||||
bool disableNaglesAlgorithm = false;
|
||||
};
|
||||
|
||||
|
||||
/*--- UDP -------------------------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
UCLASS()
|
||||
class SOCKETCLIENT_API UUDPInitAsyncNode : public UBlueprintAsyncActionBase
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
|
||||
public:
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FUDPInitDelegate, const FString, initializationInfo, const FString, clientConnectionID,
|
||||
const FString, peerIP,const int32, peerPort,
|
||||
const FString, messageFromServer, const TArray<uint8>&, byteArrayFromServer);
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FUDPInitDelegate OnSuccess;
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FUDPInitDelegate OnFail;
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FUDPInitDelegate OnServerMessage;
|
||||
|
||||
/**
|
||||
*Opens a connection on specific ip and port and listen on it.
|
||||
*@param DomainOrIP IP or Domain to listen on. 0.0.0.0 means that data can be received on all local IPs.
|
||||
*@param port port to listen on
|
||||
*@param receiveFilter This allows you to decide which data type you want to receive. If you receive files it makes no sense to convert them into a string.
|
||||
*@param maxPacketSize sets the maximum UDP packet size. More than 65507 is not possible.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|UDP", meta = (BlueprintInternalUseOnly = "true", AdvancedDisplay = 5))
|
||||
static UUDPInitAsyncNode* socketClientInitUDPReceiverAsyncNode(FString domainOrIP = "0.0.0.0",
|
||||
ESocketClientIPType ipType = ESocketClientIPType::E_ipv4, int32 port = 8888,
|
||||
EReceiveFilterClient receiveFilter = EReceiveFilterClient::E_SAB, int32 maxPacketSize = 65507);
|
||||
|
||||
|
||||
virtual void Activate() override;
|
||||
|
||||
void triggerInitEvent(bool success, FString clientConnectionID, FString serverMessage);
|
||||
void triggerMessageEvent(TArray<uint8> byteDataArray, FString clientConnectionID, FString serverMessage, FString peerIP, int32 peerPort);
|
||||
|
||||
private:
|
||||
UUDPInitAsyncNode* instance = nullptr;
|
||||
FString domainOrIP = "0.0.0.0";
|
||||
ESocketClientIPType ipType = ESocketClientIPType::E_ipv4;
|
||||
int32 port = 8888;
|
||||
EReceiveFilterClient receiveFilter = EReceiveFilterClient::E_SAB;
|
||||
int32 maxPacketSize = 65507;
|
||||
FString connectionID = FString();
|
||||
};
|
||||
+374
@@ -0,0 +1,374 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
#include "SocketClientBPLibrary.generated.h"
|
||||
|
||||
class FSocketClientCleanerThread;
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ESocketClientSystem : uint8
|
||||
{
|
||||
Android,
|
||||
IOS,
|
||||
Windows,
|
||||
Linux,
|
||||
Mac
|
||||
};
|
||||
|
||||
UENUM(BlueprintType)
|
||||
enum class ESocketClientDirectoryType : uint8
|
||||
{
|
||||
E_gd UMETA(DisplayName = "Game directory"),
|
||||
E_ad UMETA(DisplayName = "Absolute directory")
|
||||
};
|
||||
|
||||
|
||||
class USocketClientTCPClient;
|
||||
class USocketClientUDP;
|
||||
class FSocketClientUDPReceiveDataThread;
|
||||
//class FReadFileInPartsThread;
|
||||
|
||||
UCLASS()
|
||||
class SOCKETCLIENT_API USocketClientBPLibrary : public UObject
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
public:
|
||||
|
||||
~USocketClientBPLibrary();
|
||||
|
||||
|
||||
//Delegates
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FsocketClientTCPConnectionEventDelegate, bool, success, FString, message, FString, clientConnectionID);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FreceiveTCPMessageEventDelegate, FString, message, const TArray<uint8>&, byteArray, FString, clientConnectionID);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FsocketClientUDPConnectionEventDelegate, bool, success, FString, message, FString, clientConnectionID);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FiveParams(FreceiveUDPMessageEventDelegate, FString, message, const TArray<uint8>&, byteArray, FString, IP_FromSender, int32, portFromSender, FString, clientConnectionID);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FreadBytesFromFileInPartsEventDelegate, int64, fileSize, int64, position,bool, end, const TArray<uint8>&, byteArray);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FtransferFileOverTCPProgressEventDelegate, FString, clientConnectionID, FString, filePath, float, percent, float, mbit, int64, bytesTransferred, int64, fileSize);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FfileTransferOverTCPInfoEventDelegate, FString, message, FString, clientConnectionID, FString, filePath, bool, success);
|
||||
|
||||
|
||||
UFUNCTION()
|
||||
void socketClientTCPConnectionEventDelegate(const bool success, const FString message, const FString clientConnectionID);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|TCP|Events|ConnectionInfo")
|
||||
FsocketClientTCPConnectionEventDelegate onsocketClientTCPConnectionEventDelegate;
|
||||
UFUNCTION()
|
||||
void receiveTCPMessageEventDelegate(const FString message, const TArray<uint8>& byteArray, const FString clientConnectionID);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|TCP|Events|ReceiveMessage")
|
||||
FreceiveTCPMessageEventDelegate onreceiveTCPMessageEventDelegate;
|
||||
UFUNCTION()
|
||||
void socketClientUDPConnectionEventDelegate(const bool success, const FString message, const FString clientConnectionID);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|UDP|Events|ConnectionInfo")
|
||||
FsocketClientUDPConnectionEventDelegate onsocketClientUDPConnectionEventDelegate;
|
||||
UFUNCTION()
|
||||
void receiveUDPMessageEventDelegate(const FString message, const TArray<uint8>& byteArray, const FString IP, const int32 port,const FString clientConnectionID);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|UDP|Events|ReceiveMessage")
|
||||
FreceiveUDPMessageEventDelegate onreceiveUDPMessageEventDelegate;
|
||||
UFUNCTION()
|
||||
void readBytesFromFileInPartsEventDelegate(const int64 fileSize, const int64 position,const bool end, const TArray<uint8>& byteArray);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|SpecialFunctions|File|Events|ReadBytesFromFileInPartsAsync")
|
||||
FreadBytesFromFileInPartsEventDelegate onreadBytesFromFileInPartsEventDelegate;
|
||||
UFUNCTION()
|
||||
void transferFileOverTCPProgressEventDelegate(const FString clientConnectionID,const FString filePath, const float percent, const float mbit, const int64 bytesTransferred, const int64 fileSize);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|TCP|Events|File|transferFileOverTCPProgress")
|
||||
FtransferFileOverTCPProgressEventDelegate ontransferFileOverTCPProgressEventDelegate;
|
||||
UFUNCTION()
|
||||
void fileTransferOverTCPInfoEventDelegate(const FString message, const FString clientConnectionID, const FString filePath, const bool success);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|TCP|Events|File|FileTransferOverTCPInfo")
|
||||
FfileTransferOverTCPInfoEventDelegate onfileTransferOverTCPInfoEventDelegate;
|
||||
|
||||
|
||||
/**
|
||||
* Get an instance of this library. This allows non-static functions to be called.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient")
|
||||
static USocketClientBPLibrary* getSocketClientTarget();
|
||||
static USocketClientBPLibrary* socketClientBPLibrary;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Connect to a TCP Server
|
||||
* @param domainOrIP IP or Domain of your server
|
||||
* @param ipType
|
||||
* @param port
|
||||
* @param receiveFilter This allows you to decide which data type you want to receive. If you receive files it makes no sense to convert them into a string.
|
||||
* @param messageSeparator It may be that data packets are split or merged when transmitted over TCP in order to optimize the transmission. For example, if you send "Hello" two times in a row very quickly, it can happen that "HelloHa" and "llo" arrive. To counteract this circumstance there are options to separate the data packets.
|
||||
* @param optionalCustomConnectionID Instead of an automatically generated ConnectionID you can use your own ID with this parameter.
|
||||
* @param disableNaglesAlgorithm Don't change it if you don't know what this option is for! With this you can disable the TCP Nagle's algorithm to send (in LAN) very small data packets faster.
|
||||
**/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|TCP", meta = (AdvancedDisplay = 6))
|
||||
static void connectSocketClientTCP(FString domainOrIP, ESocketClientIPType ipType, int32 port, EReceiveFilterClient receiveFilters,
|
||||
ESocketClientTCPSeparator messageSeparator, FString optionalCustomConnectionID, FString& connectionID, bool disableNaglesAlgorithm = false);
|
||||
void connectSocketClientTCPNonStatic(FString domainOrIP, ESocketClientIPType ipType, int32 port, EReceiveFilterClient receiveFilters,
|
||||
ESocketClientTCPSeparator messageSeparator,FString optionalCustomConnectionID, FString &connectionID, UTCPConnectAsyncNode* tcpConnectAsyncNode, bool disableNaglesAlgorithm = false);
|
||||
|
||||
|
||||
/**
|
||||
* Sends a string or byte array to the server.
|
||||
*@param connectionID The ID to an existing connection.
|
||||
*@param message String to send
|
||||
*@param byteArray bytes to send
|
||||
*@param addLineBreak add a line break at the end
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|TCP", meta = (AutoCreateRefTerm = "byteArray"))
|
||||
static void socketClientSendTCP(FString connectionID, FString message, TArray<uint8> byteArray, bool addLineBreak = true);
|
||||
void socketClientSendTCPNonStatic(FString connectionID, FString message, TArray<uint8> byteArray, bool addLineBreak = true);
|
||||
|
||||
/**
|
||||
* Sends files as a kind of stream. This allows extremely large files to be sent since they do not have to be loaded into RAM beforehand. At the end of the transfer a MD5 checksum is created and compared between client and server to exclude errors during the transfer.
|
||||
*@param connectionID The ID to an existing connection.
|
||||
*@param domainOrIP IP or Domain of your server
|
||||
*@param directoryType Absolute or relative directory. Absolute directory starts at the disk (e.g. Windows C:\). A relative directory starts one level higher than the Content directory in the project or game.
|
||||
*@param filePath Directory including the file to be sent.
|
||||
*@param token The token is a unique ID that the client and server must know. The server knows from the token in which directory the file should be saved.
|
||||
*@param Aes256bitKey The AES key must consist of 32 ASCII characters. The communication between client and server is encrypted via AES in 256bit. Therefore a key must be entered.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|TCP")
|
||||
static void socketClientSendFileOverTCP(FString& connectionID, FString domainOrIP, ESocketClientIPType ipType, int32 port, EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, FString token, FString Aes256bitKey);
|
||||
void socketClientSendFileOverTCPNonStatic(FString& connectionID, FString domainOrIP, ESocketClientIPType ipType, int32 port, EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, FString token, FString Aes256bitKey);
|
||||
|
||||
/**
|
||||
* Lets the server send a file to this client as a kind of stream. This allows extremely large files to be sent since they do not have to be loaded into RAM beforehand. At the end of the transfer a MD5 checksum is created and compared between client and server to exclude errors during the transfer.
|
||||
*@param connectionID The ID to an existing connection.
|
||||
*@param domainOrIP IP or Domain of your server
|
||||
*@param directoryType Absolute or relative directory. Absolute directory starts at the disk (e.g. Windows C:\). A relative directory starts one level higher than the Content directory in the project or game.
|
||||
*@param filePath Directory including the file to be sent.
|
||||
*@param token The token is a unique ID that the client and server must know. The server recognizes by the toke what kind of file should be sent.
|
||||
*@param Aes256bitKey The AES key must consist of 32 ASCII characters. The communication between client and server is encrypted via AES in 256bit. Therefore a key must be entered.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|TCP")
|
||||
static void socketClientRequestFileOverTCP(FString& connectionID, FString domainOrIP, ESocketClientIPType ipType, int32 port, EFileFunctionsSocketClientDirectoryType directoryType, FString downloadDirectory, bool resume, FString token, FString Aes256bitKey);
|
||||
void socketClientRequestFileOverTCPNonStatic(FString& connectionID, FString domainOrIP, ESocketClientIPType ipType, int32 port, EFileFunctionsSocketClientDirectoryType directoryType, FString downloadDirectory, bool resume, FString token, FString Aes256bitKey);
|
||||
|
||||
/**
|
||||
* Terminates an existing connection.
|
||||
*@param connectionID The ID to an existing connection.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|TCP")
|
||||
static void closeSocketClientConnectionTCP(FString connectionID);
|
||||
void closeSocketClientConnectionTCPNonStatic(FString connectionID);
|
||||
|
||||
/**
|
||||
* Terminates all connections.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|TCP")
|
||||
static void closeAllSocketClientConnectionsTCP();
|
||||
void closeAllSocketClientConnectionsTCPNonStatic();
|
||||
|
||||
|
||||
/**
|
||||
* Useful if you want to attach events to a certain connection.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|TCP")
|
||||
static void getTCPConnectionByConnectionID(FString connectionID, bool &found, USocketClientTCPClient* &connection);
|
||||
void getTCPConnectionByConnectionIDNonStatic(FString connectionID, bool& found, USocketClientTCPClient*& connection);
|
||||
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|TCP")
|
||||
static bool isTCPConnected(FString connectionID);
|
||||
bool isTCPConnectedNonStatic(FString connectionID);
|
||||
|
||||
|
||||
/**
|
||||
*Opens a connection on specific ip and port and listen on it.
|
||||
*@param DomainOrIP IP or Domain to listen on. 0.0.0.0 means that data can be received on all local IPs.
|
||||
*@param port port to listen on
|
||||
*@param receiveFilter This allows you to decide which data type you want to receive. If you receive files it makes no sense to convert them into a string.
|
||||
*@param maxPacketSize sets the maximum UDP packet size. More than 65507 is not possible.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|UDP")
|
||||
static void socketClientInitUDPReceiver(FString& connectionID, FString domainOrIP = "0.0.0.0", ESocketClientIPType ipType = ESocketClientIPType::E_ipv4, int32 port = 8888, EReceiveFilterClient receiveFilter = EReceiveFilterClient::E_SAB, int32 maxPacketSize = 65507);
|
||||
void socketClientInitUDPReceiverNonStatic(FString& connectionID, UUDPInitAsyncNode* udpInitAsyncNode, FString domainOrIP = "0.0.0.0", ESocketClientIPType ipType = ESocketClientIPType::E_ipv4, int32 port = 8888, EReceiveFilterClient receiveFilter = EReceiveFilterClient::E_SAB, int32 maxPacketSize = 65507);
|
||||
|
||||
/**
|
||||
* A ConnectionID must be created first with "socketClientInitUDPReceiver". Messages and bytes can be sent to different hosts with the same ConnectionID.
|
||||
*@param DomainOrIP target IP or Domain
|
||||
*@param port target port
|
||||
*@param message String to send
|
||||
*@param addLineBreak add a line break at the end
|
||||
*@param uniqueID is optional and required when multiple connections to the same server (same ip and port) shall be established. You can use getUniquePlayerID
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|UDP", meta = (AutoCreateRefTerm = "byteArray"))
|
||||
static void socketClientSendUDP(FString domainOrIP, ESocketClientIPType ipType, int32 port, FString message, TArray<uint8> byteArray, bool addLineBreak = true, FString connectionID = "");
|
||||
void socketClientSendUDPNonStatic(FString domainOrIP, ESocketClientIPType ipType, int32 port, FString message, TArray<uint8> byteArray, bool addLineBreak = true, FString connectionID = "");
|
||||
|
||||
/**
|
||||
* Terminates an existing connection.
|
||||
*@param connectionID The ID to an existing connection.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|UDP")
|
||||
static void closeSocketClientConnectionUDP(FString connectionID);
|
||||
void closeSocketClientConnectionUDPNonStatic(FString connectionID);
|
||||
|
||||
/**
|
||||
* Useful if you want to attach events to a certain connection.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|UDP")
|
||||
static void getUDPInitializationByConnectionID(FString connectionID, bool& found, USocketClientUDP*& connection);
|
||||
void getUDPInitializationByConnectionIDNonStatic(FString connectionID, bool& found, USocketClientUDP*& connection);
|
||||
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|UDP")
|
||||
static bool isUDPInitialized(FString connectionID);
|
||||
bool isUDPInitializedNonStatic(FString connectionID);
|
||||
|
||||
/**
|
||||
*Trying to determine the local IP. It uses a function in the engine that does not work on all devices. On Windows and Linux it seems to work very well. Very bad on Android. 0.0.0.0 will be returned if it doesn't work.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions")
|
||||
static FString getLocalIP();
|
||||
|
||||
|
||||
/**
|
||||
*UE4 uses different socket connections. When Steam is active, Steam Sockets are used for all connections. This leads to problems if you want to use Steam but not Steam Sockets. Therefore you can change the sockets to "System".
|
||||
*@param ESocketPlatformServer System = Windows on Windows, Mac = Mac on Mac ect.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions")
|
||||
static void changeSocketPlatform(ESocketPlatformClient platform);
|
||||
|
||||
|
||||
/**
|
||||
*The cleaner thread is a thread that runs endlessly and deletes data remnants from closed/broken connections from RAM.
|
||||
*@param showLogs Writes to the logs when data remnants are deleted.
|
||||
*@param minLiveTimeInSeconds When a connection is closed it is passed to the cleaner thread. The thread ignores the connection for "minLiveTimeInSeconds" until it clears the data. This is necessary because sometimes connections need some time to be closed completely.
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions")
|
||||
static void changeCleanerThreadSettingsOnClient(bool showLogs, int32 minLiveTimeInSeconds = 10);
|
||||
|
||||
/**
|
||||
* Returns which system you are currently use. (Windows, OSX, IOS ...)
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions", Meta = (ExpandEnumAsExecs = "system"))
|
||||
static void getSystemType(ESocketClientSystem& system);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions")
|
||||
static int32 getUniquePlayerID(APlayerController* playerController = nullptr);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions")
|
||||
static FString getRandomID();
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Hex")
|
||||
static TArray<uint8> parseHexToBytes(FString hex);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Hex")
|
||||
static FString parseHexToString(FString hex);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Hex")
|
||||
static FString parseBytesToHex(TArray<uint8> bytes);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Hex")
|
||||
static TArray<uint8> parseHexToBytesPure(FString hex);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Hex")
|
||||
static FString parseHexToStringPure(FString hex);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Hex")
|
||||
static FString parseBytesToHexPure(TArray<uint8> bytes);
|
||||
|
||||
|
||||
//number stuff
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Number")
|
||||
static void parseBytesToFloat(TArray<uint8> bytes, float& value);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Number")
|
||||
static void parseBytesToInteger(TArray<uint8> bytes, int32& value);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Number")
|
||||
static void parseBytesToInteger64(TArray<uint8> bytes, int64& value);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number")
|
||||
static void parseBytesToFloatPure(TArray<uint8> bytes, float& value);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number")
|
||||
static void parseBytesToIntegerPure(TArray<uint8> bytes, int32& value);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number")
|
||||
static void parseBytesToInteger64Pure(TArray<uint8> bytes, int64& value);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Number")
|
||||
static void parseBytesToFloatEndian(TArray<uint8> bytes, float& littleEndian, float& bigEndian);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Number")
|
||||
static void parseBytesToIntegerEndian(TArray<uint8> bytes, int32& littleEndian, int32& bigEndian);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Number")
|
||||
static void parseBytesToInteger64Endian(TArray<uint8> bytes, int64& littleEndian, int64& bigEndian);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "byteArray"))
|
||||
static void parseFloatToBytes(TArray<uint8>& byteArray, float value, bool switchByteOrder = false);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "byteArray"))
|
||||
static void parseIntegerToBytes(TArray<uint8>& byteArray, int32 value, bool switchByteOrder = false);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "byteArray"))
|
||||
static void parseInteger64ToBytes(TArray<uint8>& byteArray, int64 value, bool switchByteOrder = false);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "byteArray"))
|
||||
static void parseFloatToBytesPure(TArray<uint8>& byteArray, float value, bool switchByteOrder = false);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "byteArray"))
|
||||
static void parseIntegerToBytesPure(TArray<uint8>& byteArray, int32 value, bool switchByteOrder = false);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "byteArray"))
|
||||
static void parseInteger64ToBytesPure(TArray<uint8>& byteArray, int64 value, bool switchByteOrder = false);
|
||||
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "value"))
|
||||
static void parseBytesToFloatArrayPure(TArray<float>& value, TArray<uint8> bytes);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "value"))
|
||||
static void parseBytesToIntegerArrayPure(TArray<int32>& value, TArray<uint8> bytes);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "value"))
|
||||
static void parseBytesToInteger64ArrayPure(TArray<int64>& value, TArray<uint8> bytes);
|
||||
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "byteArray"))
|
||||
static void parseFloatArrayToBytesPure(TArray<uint8>& byteArray, TArray<float> value);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "byteArray"))
|
||||
static void parseIntegerArrayToBytesPure(TArray<uint8>& byteArray, TArray<int32> value);
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "SocketClient|SpecialFunctions|Number", meta = (AutoCreateRefTerm = "byteArray"))
|
||||
static void parseInteger64ArrayToBytesPure(TArray<uint8>& byteArray, TArray<int64> value);
|
||||
|
||||
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|TCP")
|
||||
static void changeTCPSeparatorStringOnClient(FString separator = "(~{");
|
||||
void changeTCPSeparatorStringOnClientNonStatic(FString separator);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category = "SocketClient|TCP")
|
||||
static void changeTCPSeparatorByteOnClient(uint8 separator = 0x00);
|
||||
void changeTCPSeparatorByteOnClientNonStatic(uint8 separator);
|
||||
|
||||
|
||||
void getTcpSeparator(uint8& byteSeparator, FString& stringSeparator);
|
||||
|
||||
static ISocketSubsystem* getSocketSubSystem();
|
||||
|
||||
FString resolveDomain(FString domain, ESocketClientIPType ipType);
|
||||
//ue4 domain resolve does not work with steam. this is my own dns client
|
||||
class UDNSClientSocketClient* dnsClient = nullptr;
|
||||
TMap<FString, FString> domainCache;
|
||||
|
||||
|
||||
void cleanConnection(FSocketClientPluginSession& session);
|
||||
|
||||
private:
|
||||
ESocketPlatformClient systemSocketPlatform;
|
||||
|
||||
TMap<FString, USocketClientTCPClient*> tcpClients;
|
||||
TMap<FString, USocketClientUDP*> udpClients;
|
||||
//TMap<FString, FReadFileInPartsThread*> readFileInPartsThreads;
|
||||
|
||||
int64 lastErrorMessageTime = 0;
|
||||
|
||||
FString tcpStringSeparator = "(~{";
|
||||
uint8 tcpByteSeparator = 0x00;
|
||||
|
||||
FSocketClientCleanerThread* socketClientCleanerThread = nullptr;
|
||||
};
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright 2022 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
|
||||
|
||||
class SOCKETCLIENT_API FSocketClientCleanerThread : public FRunnable {
|
||||
|
||||
public:
|
||||
|
||||
FSocketClientCleanerThread();
|
||||
|
||||
|
||||
virtual uint32 Run() override;
|
||||
|
||||
void addSession(FSocketClientPluginSession& session);
|
||||
void changeSettings(bool showLogs, int32 minLiveTimeInSeconds);
|
||||
|
||||
private:
|
||||
bool showLogs = false;
|
||||
int32 minLiveTimeInSeconds = 10;
|
||||
FRunnableThread* thread = nullptr;
|
||||
TQueue<FSocketClientPluginSession> sessionQueue;
|
||||
};
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
#include "SocketClientTCPReceiveDataThread.h"
|
||||
#include "SocketClientTCPSendDataThead.h"
|
||||
#include "SocketClientTCPFileHandlerThread.h"
|
||||
#include "SocketClientTCP.generated.h"
|
||||
|
||||
class USocketServerBPLibrary;
|
||||
|
||||
UCLASS(Blueprintable, BlueprintType)
|
||||
class SOCKETCLIENT_API USocketClientTCPClient : public UObject
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
public:
|
||||
|
||||
//Delegates
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FsocketClientTCPConnectionEventDelegate, bool, success, FString, message, FString, clientConnectionID);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FreceiveTCPMessageEventDelegate, FString, message, const TArray<uint8>&, byteArray, FString, clientConnectionID);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FtransferFileOverTCPProgressEventDelegate, FString, clientConnectionID, FString, filePath, float, percent, float, mbit, int64, bytesTransferred, int64, fileSize);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FourParams(FfileTransferOverTCPInfoEventDelegate, FString, message, FString, clientConnectionID, FString, filePath, bool, success);
|
||||
|
||||
UFUNCTION()
|
||||
void socketClientTCPConnectionEventDelegate(const bool success, const FString message, const FString clientConnectionID);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|TCP|Events|ConnectionInfo")
|
||||
FsocketClientTCPConnectionEventDelegate onsocketClientTCPConnectionEventDelegate;
|
||||
UFUNCTION()
|
||||
void receiveTCPMessageEventDelegate(const FString message, const TArray<uint8>& byteArray, const FString clientConnectionID);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|TCP|Events|ReceiveMessage")
|
||||
FreceiveTCPMessageEventDelegate onreceiveTCPMessageEventDelegate;
|
||||
UFUNCTION()
|
||||
void transferFileOverTCPProgressEventDelegate(const FString clientConnectionID, const FString filePath, const float percent, const float mbit, const int64 bytesTransferred, const int64 fileSize);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|TCP|Events|File|transferFileOverTCPProgress")
|
||||
FtransferFileOverTCPProgressEventDelegate ontransferFileOverTCPProgressEventDelegate;
|
||||
UFUNCTION()
|
||||
void fileTransferOverTCPInfoEventDelegate(const FString message, const FString clientConnectionID, const FString filePath, const bool success);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|TCP|Events|File|FileTransferOverTCPInfo")
|
||||
FfileTransferOverTCPInfoEventDelegate onfileTransferOverTCPInfoEventDelegate;
|
||||
|
||||
UFUNCTION()
|
||||
void connectionEvent(bool success, FString message, FString clientConnectionID);
|
||||
|
||||
void connect(USocketClientBPLibrary* mainLib, FString domainOrIP, ESocketClientIPType ipType, int32 port, EReceiveFilterClient receiveFilter,
|
||||
ESocketClientTCPSeparator messageWrapping, FString connectionID, UTCPConnectAsyncNode* tcpConnectAsyncNode, bool noPacketDelay = false, bool noPacketBlocking = false);
|
||||
void sendMessage(FString message, TArray<uint8> byteArray);
|
||||
void sendFile(USocketClientBPLibrary* mainLib, FString connectionID, FString domainOrIP, ESocketClientIPType ipType, int32 port, EFileFunctionsSocketClientDirectoryType directoryType, FString filePath, FString token, FString Aes256bitKey);
|
||||
void requestFile(USocketClientBPLibrary* mainLib, FString connectionID, FString domainOrIP, ESocketClientIPType ipType, int32 port, EFileFunctionsSocketClientDirectoryType directoryType, FString filePath,bool resume, FString token, FString Aes256bitKey);
|
||||
|
||||
void closeConnection();
|
||||
|
||||
bool isRun();
|
||||
void setRun(bool runP);
|
||||
FString getConnectionID();
|
||||
FString getAesKey();
|
||||
FString getFileToken();
|
||||
FString getFilePath();
|
||||
|
||||
void setSocket(FSocket* socket);
|
||||
FSocket* getSocket();
|
||||
USocketClientBPLibrary* getMainLib();
|
||||
|
||||
void createSendThread();
|
||||
//void createFileSendThread(int64 startPosition);
|
||||
FString encryptMessage(FString message);
|
||||
FString decryptMessage(FString message);
|
||||
void readDataLength(TArray<uint8>& byteDataArray, int32& byteLenght);
|
||||
bool isSendFile();
|
||||
bool isReceiveFile();
|
||||
bool hasResume();
|
||||
bool isConnected();
|
||||
void deleteFile(FString filePathP);
|
||||
void getMD5FromFileAbsolutePath(FString filePath, bool& success, FString& MD5);
|
||||
int64 fileSize(FString filePath);
|
||||
FString int64ToString(int64 num);
|
||||
void getTcpSeparator(FString& stringSeparator, uint8& byteSeparator, ESocketClientTCPSeparator& messageWrapping);
|
||||
|
||||
UTCPConnectAsyncNode* tcpConnectAsyncNode = nullptr;
|
||||
|
||||
private:
|
||||
|
||||
bool run = false;
|
||||
bool connected = false;
|
||||
bool resume = false;
|
||||
int32 sendOrReceive = -1; //0 == send, 1 == receive;
|
||||
FString connectionID = FString();
|
||||
FString aesKey = FString();
|
||||
FString fileToken = FString();
|
||||
FString filePath = FString();
|
||||
|
||||
|
||||
FSocket* socket = nullptr;
|
||||
|
||||
FSocketClientTCPReceiveDataThread* tcpReceiveDataThread = nullptr;
|
||||
FSocketClientTCPSendDataThead* tcpSendThread = nullptr;
|
||||
FSocketClientTCPFileHandlerThread* tcpFileConnectionThread = nullptr;
|
||||
//FSocketClientTCPSendFileThread* fileSendThread = nullptr;
|
||||
USocketClientBPLibrary* mainLib = nullptr;
|
||||
|
||||
|
||||
ESocketClientTCPSeparator messageWrapping;
|
||||
FString tcpStringSeparator = "(~{";
|
||||
uint8 tcpByteSeparator = 0x00;
|
||||
|
||||
};
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// Copyright 2022 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
|
||||
|
||||
class SOCKETCLIENT_API FSocketClientTCPFileHandlerThread : public FRunnable {
|
||||
|
||||
public:
|
||||
|
||||
FSocketClientTCPFileHandlerThread(USocketClientBPLibrary* socketClientP, FString clientConnectionIDP, FString ipOrDomainP, ESocketClientIPType ipTypeP,
|
||||
int32 portP, USocketClientTCPClient* tcpClientP);
|
||||
|
||||
~FSocketClientTCPFileHandlerThread();
|
||||
|
||||
virtual uint32 Run() override;
|
||||
|
||||
void doRequestFileFromServer(FSocket* socket);
|
||||
void doSendFileToServer(FSocket* socket);
|
||||
|
||||
void sendMessageToServer(FString message, FSocket* socket);
|
||||
|
||||
void triggerFileTransferOverTCPInfoEvent(FString messageP, FString clientConnectionIDP, FString filePathP, bool successP,
|
||||
USocketClientBPLibrary* socketClientP, USocketClientTCPClient* tcpClientP);
|
||||
|
||||
void triggerTransferFileEvent(FString clientConnectionIDP, FString filePathP, USocketClientBPLibrary* socketClientP,
|
||||
USocketClientTCPClient* tcpClientP, float percentP, float mbitP, int64 transferredP, int64 fileSizeP);
|
||||
|
||||
void sendEndMessage(FString fullFilePathP, FString tokenP, FString md5ServerP, FString clientConnectionIDP, FSocket* clientSocketP,
|
||||
USocketClientBPLibrary* socketClientP, USocketClientTCPClient* tcpClientP);
|
||||
|
||||
FString readMessageFromServer(FSocket* socket);
|
||||
|
||||
private:
|
||||
USocketClientBPLibrary* socketClient = nullptr;
|
||||
//USocketClientBPLibrary* oldClient;
|
||||
FString clientConnectionID;
|
||||
FString originalIP;
|
||||
FString ipOrDomain;
|
||||
ESocketClientIPType ipType;
|
||||
int32 port;
|
||||
USocketClientTCPClient* tcpClient = nullptr;
|
||||
FRunnableThread* thread = nullptr;
|
||||
double waitForRead = 30;
|
||||
};
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
// Copyright 2022 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
|
||||
|
||||
class SOCKETCLIENT_API FSocketClientTCPReceiveDataThread : public FRunnable {
|
||||
|
||||
public:
|
||||
|
||||
FSocketClientTCPReceiveDataThread(USocketClientBPLibrary* socketClientBPLibraryP, FString clientConnectionIDP, EReceiveFilterClient receiveFilterP,
|
||||
FString ipOrDomainP, ESocketClientIPType ipTypeP,int32 portP, USocketClientTCPClient* tcpClientP, bool noPacketDelayP, bool noPacketBlockingP);
|
||||
|
||||
~FSocketClientTCPReceiveDataThread();
|
||||
|
||||
virtual uint32 Run() override;
|
||||
|
||||
|
||||
void triggerConnectionEvent(bool succsess, FString clientConnectionIDGlobal, FString serverMessage, USocketClientTCPClient* tcpClientGlobal,
|
||||
USocketClientBPLibrary* socketClientGlobal);
|
||||
void triggerMessageEvent(TArray<uint8>& byteDataArray, FString& clientConnectionIDGlobal, USocketClientTCPClient* tcpClientGlobal,
|
||||
USocketClientBPLibrary* socketClientGlobal, bool addNullTerminator = true);
|
||||
|
||||
|
||||
private:
|
||||
USocketClientBPLibrary* socketClientBPLibrary = nullptr;
|
||||
//USocketClientBPLibrary* oldClient;
|
||||
FString clientConnectionID;
|
||||
FString originalIP;
|
||||
EReceiveFilterClient receiveFilter;
|
||||
FString ipOrDomain;
|
||||
ESocketClientIPType ipType;
|
||||
int32 port;
|
||||
USocketClientTCPClient* tcpClient = nullptr;
|
||||
bool noPacketDelay = false;
|
||||
bool noPacketBlocking = false;
|
||||
|
||||
|
||||
FRunnableThread* thread = nullptr;
|
||||
};
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// Copyright 2022 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
|
||||
class SOCKETCLIENT_API FSocketClientTCPSendDataThead : public FRunnable {
|
||||
|
||||
public:
|
||||
|
||||
FSocketClientTCPSendDataThead(USocketClientBPLibrary* socketClientLibP, USocketClientTCPClient* tcpClientP, FString clientConnectionIDP);
|
||||
|
||||
~FSocketClientTCPSendDataThead();
|
||||
|
||||
virtual uint32 Run() override;
|
||||
void sendMessage(FString messageP, TArray<uint8> byteArrayP);
|
||||
void pauseThread(bool pause);
|
||||
|
||||
|
||||
private:
|
||||
TQueue<FString> messageQueue;
|
||||
TQueue<TArray<uint8>> byteArrayQueue;
|
||||
USocketClientBPLibrary* socketClientLib;
|
||||
USocketClientTCPClient* tcpClient = nullptr;
|
||||
FString clientConnectionID;
|
||||
FRunnableThread* thread = nullptr;
|
||||
bool run = true;
|
||||
bool paused = false;
|
||||
bool blah = true;
|
||||
};
|
||||
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
// Copyright 2017-2019 David Romanski (Socke). All Rights Reserved.
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
#include "SocketClientUDPSendDataThead.h"
|
||||
#include "SocketClientUDPReceiveDataThread.h"
|
||||
#include "SocketClientUDP.generated.h"
|
||||
|
||||
|
||||
class USocketClientBPLibrary;
|
||||
|
||||
UCLASS(Blueprintable, BlueprintType)
|
||||
class SOCKETCLIENT_API USocketClientUDP : public UObject
|
||||
{
|
||||
GENERATED_UCLASS_BODY()
|
||||
|
||||
public:
|
||||
|
||||
//Delegates
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FsocketClientUDPConnectionEventDelegate, bool, success, FString, message, FString, clientConnectionID);
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_FiveParams(FreceiveUDPMessageEventDelegate, FString, message, const TArray<uint8>&, byteArray, FString, IP_FromSender, int32, portFromSender, FString, clientConnectionID);
|
||||
|
||||
UFUNCTION()
|
||||
void socketClientUDPConnectionEventDelegate(const bool success, const FString message, const FString clientConnectionID);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|UDP|Events|ConnectionInfo")
|
||||
FsocketClientUDPConnectionEventDelegate onsocketClientUDPConnectionEventDelegate;
|
||||
UFUNCTION()
|
||||
void receiveUDPMessageEventDelegate(const FString message, const TArray<uint8>& byteArray, const FString IP, const int32 port, const FString clientConnectionID);
|
||||
UPROPERTY(BlueprintAssignable, Category = "SocketClient|UDP|Events|ReceiveMessage")
|
||||
FreceiveUDPMessageEventDelegate onreceiveUDPMessageEventDelegate;
|
||||
|
||||
void init(USocketClientBPLibrary* socketClientLibP, UUDPInitAsyncNode* udpInitAsyncNode, FString domain, ESocketClientIPType ipType, int32 port, EReceiveFilterClient receiveFilter, FString clientConnectionID, int32 maxPacketSize = 65507);
|
||||
void sendUDPMessage(FString domainOrIP, ESocketClientIPType ipType, int32 port, FString message, TArray<uint8> byteArray);
|
||||
void closeUDPConnection();
|
||||
void UDPReceiver(const FArrayReaderPtr& ArrayReaderPtr, const FIPv4Endpoint& EndPt);
|
||||
|
||||
|
||||
bool isRun();
|
||||
void setRun(bool runP);
|
||||
|
||||
FSocket* getSocket();
|
||||
void setSocket(FSocket* socketP);
|
||||
|
||||
void setUDPSocketReceiver(FUdpSocketReceiver* udpSocketReceiver);
|
||||
|
||||
FString getIP();
|
||||
void setIP(FString ipP);
|
||||
int32 getPort();
|
||||
FString getDomainOrIP();
|
||||
|
||||
FString getConnectionID();
|
||||
void setUDPSendThread(FSocketClientUDPSendDataThead* udpSendThreadP);
|
||||
|
||||
int32 getMaxPacketSize();
|
||||
|
||||
UUDPInitAsyncNode* udpInitAsyncNode = nullptr;
|
||||
|
||||
private:
|
||||
bool run = false;
|
||||
EReceiveFilterClient receiveFilter;
|
||||
FString connectionID;
|
||||
FString domainOrIP;
|
||||
int32 port = 0;
|
||||
int32 maxPacketSize = 65507;
|
||||
|
||||
USocketClientBPLibrary* socketClientBPLibrary = nullptr;
|
||||
|
||||
FUdpSocketReceiver* udpSocketReceiver = nullptr;
|
||||
FSocket* socket = nullptr;
|
||||
FSocketClientUDPReceiveDataThread* UDPThread = nullptr;
|
||||
FSocketClientUDPSendDataThead* UDPSendThread = nullptr;
|
||||
};
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// Copyright 2022 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
|
||||
|
||||
class SOCKETCLIENT_API FSocketClientUDPReceiveDataThread : public FRunnable {
|
||||
|
||||
public:
|
||||
|
||||
FSocketClientUDPReceiveDataThread(USocketClientUDP* udpClientP, USocketClientBPLibrary* socketClientP, FString ipP, int32 portP, ESocketClientIPType ipTypeP);
|
||||
|
||||
~FSocketClientUDPReceiveDataThread();
|
||||
|
||||
void triggerInitEvent(bool success, USocketClientUDP* udpClientP, USocketClientBPLibrary* socketClientP, FString serverMessage, FString connectionID);
|
||||
|
||||
virtual uint32 Run() override;
|
||||
|
||||
|
||||
private :
|
||||
USocketClientUDP* udpClient = nullptr;
|
||||
USocketClientBPLibrary* socketClient = nullptr;
|
||||
FRunnableThread* thread = nullptr;
|
||||
FString ipGlobal;
|
||||
int32 portGlobal;
|
||||
ESocketClientIPType ipType = ESocketClientIPType::E_ipv4;
|
||||
FSocket* socket = nullptr;
|
||||
bool reuseSocket = false;
|
||||
};
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
// Copyright 2022 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "SocketClient.h"
|
||||
|
||||
class SOCKETCLIENT_API FSocketClientUDPSendDataThead : public FRunnable {
|
||||
|
||||
public:
|
||||
|
||||
FSocketClientUDPSendDataThead(USocketClientUDP* udpClientP, USocketClientBPLibrary* socketClientP, FString mySocketipP, int32 mySocketportP);
|
||||
|
||||
~FSocketClientUDPSendDataThead();
|
||||
|
||||
virtual uint32 Run() override;
|
||||
void addData(FString messageP, TArray<uint8> byteArrayP, FString domainOrIP, int32 port, ESocketClientIPType ipType);
|
||||
void pauseThread(bool pause);
|
||||
void sendBytes(FSocket*& socketP, TArray<uint8>& byteArray, int32& sent, TSharedRef<FInternetAddr>& addr);
|
||||
|
||||
private:
|
||||
USocketClientUDP* udpClient = nullptr;
|
||||
USocketClientBPLibrary* socketClient = nullptr;
|
||||
FString mySocketip;
|
||||
int32 mySocketport = 0;
|
||||
FString sendToip;
|
||||
int32 sendToport = 0;
|
||||
FString sendToDomainOrIP = FString();
|
||||
FRunnableThread* thread = nullptr;
|
||||
bool paused;
|
||||
TQueue<FString> messageQueue;
|
||||
TQueue<TArray<uint8>> byteArrayQueue;
|
||||
int32 maxPacketSize = 65507;
|
||||
bool validInternetAdress = false;
|
||||
TSharedRef<FInternetAddr> internetAdress = USocketClientBPLibrary::getSocketSubSystem()->CreateInternetAddr();
|
||||
int64 lastErrorMessageTime = 0;
|
||||
};
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
// Copyright 2017-2020 David Romanski (Socke). All Rights Reserved.
|
||||
|
||||
using UnrealBuildTool;
|
||||
|
||||
public class SocketClient : ModuleRules
|
||||
{
|
||||
public SocketClient(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicIncludePaths.AddRange(
|
||||
new string[] {
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PrivateIncludePaths.AddRange(
|
||||
new string[] {
|
||||
"SocketClient/Private",
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"Core",
|
||||
"Networking",
|
||||
"Sockets"
|
||||
|
||||
// ... add other public dependencies that you statically link with here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"CoreUObject",
|
||||
"Engine",
|
||||
"Networking",
|
||||
"Sockets",
|
||||
"Slate",
|
||||
"SlateCore"
|
||||
// ... add private dependencies that you statically link with here ...
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
DynamicallyLoadedModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
// ... add any modules that your module loads dynamically here ...
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user