Files
UE_SpaceStudio/SpaceStudioClient/Plugins/SocketServer/Source/SocketServer/Private/RCONServer.cpp
T
2025-09-15 17:17:30 +08:00

208 lines
6.1 KiB
C++

// Copyright 2017-2020 David Romanski (Socke). All Rights Reserved.
#include "RCONServer.h"
URCONServer::URCONServer(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) {
}
void URCONServer::startRCONServer(FString serverID, ERCONPasswordType passwordTypeP, FString passwordOrFileP
, bool& success, FString& errorMessage) {
success = false;
errorMessage = "";
if (serverID.IsEmpty() || USocketServerBPLibrary::getSocketServerTarget()->getTcpServerMap().Find(serverID) == nullptr) {
UE_LOG(LogTemp, Warning, TEXT("SimpleSocketServer Plugin (RCON): ServerID not found: %s"), *serverID);
success = false;
errorMessage = "ServerID not found: "+serverID;
return;
}
passwordType = passwordTypeP;
if (passwordType != ERCONPasswordType::E_parameter) {
EFileFunctionsSocketServerDirectoryType passwordDirectoryType = EFileFunctionsSocketServerDirectoryType::E_gd;
if (passwordType == ERCONPasswordType::E_ad) {
passwordDirectoryType = EFileFunctionsSocketServerDirectoryType::E_ad;
}
passwordOrFile = UFileFunctionsSocketServer::getCleanDirectory(passwordDirectoryType, passwordOrFileP);
if (FPaths::DirectoryExists(FPaths::GetPath(passwordOrFile)) == false) {
UFileFunctionsSocketServer::createDirectory(passwordDirectoryType, FPaths::GetPath(passwordOrFile));
}
if (FPaths::FileExists(passwordOrFile) == false) {
UFileFunctionsSocketServer::writeStringToFile(passwordDirectoryType, "", passwordOrFile, EFileFunctionsSocketServerEncodingOptions::E_AutoDetect, success);
}
if (FPaths::FileExists(passwordOrFile) == false) {
UE_LOG(LogTemp, Warning, TEXT("SimpleSocketServer Plugin (RCON): Can't read the password file: %s"), *passwordOrFile);
success = false;
errorMessage = "Can't read the password file: " + passwordOrFile;
return;
}
}
else {
passwordOrFile = passwordOrFileP;
}
success = true;
}
void URCONServer::receiveTCPMessageEvent(const FString sessionID, const FString message, const TArray<uint8>& byteArray, const FString serverID) {
USocketServerTCP* tcpServer = *USocketServerBPLibrary::getSocketServerTarget()->getTcpServerMap().Find(serverID);
if (tcpServer == nullptr) {
UE_LOG(LogTemp, Warning, TEXT("SimpleSocketServer Plugin (RCON): Server not found: %s"), *serverID);
return;
}
//https://developer.valvesoftware.com/wiki/Source_RCON_Protocol
//packet to small
if (byteArray.Num() < 14) {
tcpServer->removeClientSession(sessionID);
return;
}
//packet to big
if (byteArray.Num() > 4096) {
tcpServer->removeClientSession(sessionID);
return;
}
int32 size = 0;
FMemory::Memcpy(&size, byteArray.GetData(), 4);
//packet to small
if (size < 10) {
tcpServer->removeClientSession(sessionID);
return;
}
int32 id = 0;
FMemory::Memcpy(&id, byteArray.GetData() + 4, 4);
int32 type = 0;
FMemory::Memcpy(&type, byteArray.GetData() + 8, 4);
TArray<uint8> bodyTextArray;
bodyTextArray.AddUninitialized(byteArray.Num()-12);
FMemory::Memcpy(bodyTextArray.GetData(), byteArray.GetData() + 12, byteArray.Num() - 12);
FString bodyText = FString(UTF8_TO_TCHAR(bodyTextArray.GetData()));
bodyTextArray.Empty();
UE_LOG(LogTemp, Warning, TEXT("SimpleSocketServer Plugin (RCON): size:%i id:%i type:%i body:%s"),size, id,type,*bodyText);
switch (type)
{
case 0:
UE_LOG(LogTemp, Warning, TEXT("SimpleSocketServer Plugin (RCON): Server response sent to the server? Request will be ignored."));
break;
case 2:
USocketServerBPLibrary::getSocketServerTarget()->onreceiveRCONRequestEventDelegate.Broadcast(sessionID,serverID,id, bodyText);
break;
case 3:
authResponse(sessionID, serverID, bodyText, id);
break;
default:
UE_LOG(LogTemp, Warning, TEXT("SimpleSocketServer Plugin (RCON): Unsupported request. Connection is closed."));
tcpServer->removeClientSession(sessionID);
return;
}
}
void URCONServer::authResponse(FString sessionID, FString serverID, FString password, int32 rconID){
//check password
if (password.IsEmpty() || passwordOrFile.IsEmpty()) {
rconID = -1;
sendResponse(sessionID, serverID, -1, 2, FString());
return;
}
bool found = false;
if (passwordType == ERCONPasswordType::E_parameter) {
if (password.Equals(passwordOrFile)) {
found = true;
}
}
else {
FString passwordData = FString();
FFileHelper::LoadFileToString(passwordData, *passwordOrFile);
TArray<FString> passwords;
passwordData.ParseIntoArray(passwords, TEXT("\n"), true);
for (int32 i = 0; i < passwords.Num(); i++)
{
if (passwords[i].TrimEnd().Equals(password)) {
found = true;
break;
}
}
}
if (found) {
sendResponse(sessionID, serverID, rconID, 2, FString());
}
else {
sendResponse(sessionID, serverID, -1, 2, FString());
USocketServerTCP* tcpServer = *USocketServerBPLibrary::getSocketServerTarget()->getTcpServerMap().Find(serverID);
if (tcpServer != nullptr) {
tcpServer->removeClientSession(sessionID);
UE_LOG(LogTemp, Warning, TEXT("SimpleSocketServer Plugin (RCON): Wrong password. Connection is closed."));
}
}
}
bool URCONServer::sendResponse(FString sessionID, FString serverID, int32 id, int32 type, FString body){
USocketServerTCP* tcpServer = *USocketServerBPLibrary::getSocketServerTarget()->getTcpServerMap().Find(serverID);
if (tcpServer == nullptr) {
UE_LOG(LogTemp, Warning, TEXT("SimpleSocketServer Plugin (RCON): Server not found. Can't send response: %s"), *serverID);
return false;
}
FTCHARToUTF8 Convert(*body);
//4 (id) + 4 (type) + 1 (minimum body) + 1 (null terminator) = 10
int32 size = 10;
TArray<uint8> response;
size += Convert.Length();
response.AddZeroed(size + 4); // 4 = the size itself as int32
FMemory::Memcpy(response.GetData(), &size, 4);
FMemory::Memcpy(response.GetData() + 4, &id, 4);
FMemory::Memcpy(response.GetData() + 8, &type, 4);
if (Convert.Length() > 0) {
FMemory::Memcpy(response.GetData() + 12, Convert.Get(), Convert.Length());
}
//packet to big
if (response.Num() > 4096) {
UE_LOG(LogTemp, Warning, TEXT("SimpleSocketServer Plugin (RCON): Answer too big. A data packet may have a maximum size of 4096 bytes. Size is %i"), response.Num());
return false;
}
tcpServer->sendTCPMessageToClient(sessionID, FString(), response, false);
return true;
}