rewrite
This commit is contained in:
Anonymous275
2020-08-21 20:58:10 +03:00
parent 232c4d7b28
commit 31c96cee94
59 changed files with 4247 additions and 1212 deletions

172
src/Network/Auth.cpp Normal file
View File

@@ -0,0 +1,172 @@
///
/// Created by Anonymous275 on 7/31/2020
///
#include "Security/Enc.h"
#include "Curl/Http.h"
#include "Settings.h"
#include "Network.h"
#include "Logger.h"
#include <sstream>
#include <thread>
struct Hold{
SOCKET TCPSock{};
bool Done = false;
};
bool Send(SOCKET TCPSock,std::string Data){
int BytesSent;
BytesSent = send(TCPSock, Data.c_str(), int(Data.size()), 0);
Data.clear();
if (BytesSent <= 0)return false;
return true;
}
std::string Rcv(SOCKET TCPSock){
char buf[6768];
int len = 6768;
ZeroMemory(buf, len);
int BytesRcv = recv(TCPSock, buf, len,0);
if (BytesRcv <= 0)return "";
return std::string(buf);
}
std::string GetRole(const std::string &DID){
if(!DID.empty()){
std::string a = HttpRequest(Sec("https://beamng-mp.com/entitlement?did=")+DID,443);
if(!a.empty()){
auto pos = a.find('"');
if(pos != std::string::npos){
return a.substr(pos+1,a.find('"',pos+1)-2);
}else if(a == "[]")return Sec("Member");
}
}
return "";
}
void Check(Hold* S){
std::this_thread::sleep_for(std::chrono::seconds(5));
if(S != nullptr){
if(!S->Done)closesocket(S->TCPSock);
}
}
int Max(){
int M = MaxPlayers;
for(Client*c : CI->Clients){
if(c != nullptr){
if(c->GetRole() == Sec("MDEV"))M++;
}
}
return M;
}
void CreateClient(SOCKET TCPSock,const std::string &Name, const std::string &DID,const std::string &Role) {
auto *c = new Client;
c->SetTCPSock(TCPSock);
c->SetName(Name);
c->SetRole(Role);
c->SetDID(DID);
CI->AddClient(c);
InitClient(c);
}
std::string GenerateM(RSA*key){
std::stringstream stream;
stream << std::hex << key->n << "g" << key->e << "g" << RSA_E(Sec("IDC"),key);
return stream.str();
}
void Identification(SOCKET TCPSock,Hold*S,RSA*key){
S->TCPSock = TCPSock;
std::thread Timeout(Check,S);
Timeout.detach();
std::string Name,DID,Role;
if(!Send(TCPSock,GenerateM(key))){
closesocket(TCPSock);
return;
}
std::string Res = Rcv(TCPSock);
std::string Ver = Rcv(TCPSock);
S->Done = true;
Ver = RSA_D(Ver,key);
if(Ver.size() > 3 && Ver.substr(0,2) == Sec("VC")){
Ver = Ver.substr(2);
if(Ver.length() > 4 || Ver != GetCVer()){
closesocket(TCPSock);
return;
}
}else{
closesocket(TCPSock);
return;
}
Res = RSA_D(Res,key);
if(Res.size() < 3 || Res.substr(0,2) != Sec("NR")) {
closesocket(TCPSock);
return;
}
if(Res.find(':') == std::string::npos){
closesocket(TCPSock);
return;
}
Name = Res.substr(2,Res.find(':')-2);
DID = Res.substr(Res.find(':')+1);
Role = GetRole(DID);
if(Role.empty() || Role.find(Sec("Error")) != -1){
closesocket(TCPSock);
return;
}
debug(Sec("Name -> ") + Name + Sec(", Role -> ") + Role + Sec(", ID -> ") + DID);
for(Client*c: CI->Clients){
if(c != nullptr){
if(c->GetDID() == DID){
closesocket(c->GetTCPSock());
c->SetStatus(-2);
break;
}
}
}
if(Role == Sec("MDEV") || CI->Size() < Max()){
CreateClient(TCPSock,Name,DID,Role);
}else closesocket(TCPSock);
}
void Identify(SOCKET TCPSock){
auto* S = new Hold;
RSA*key = GenKey();
__try{
Identification(TCPSock,S,key);
}__except(1){}
delete key;
delete S;
}
void TCPServerMain(){
WSADATA wsaData;
if (WSAStartup(514, &wsaData)){
error(Sec("Can't start Winsock!"));
return;
}
SOCKET client, Listener = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
sockaddr_in addr{};
addr.sin_addr.S_un.S_addr = ADDR_ANY;
addr.sin_family = AF_INET;
addr.sin_port = htons(Port);
if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR){
error(Sec("Can't bind socket! ") + std::to_string(WSAGetLastError()));
std::this_thread::sleep_for(std::chrono::seconds(5));
exit(-1);
}
if(Listener == -1){
error(Sec("Invalid listening socket"));
return;
}
if(listen(Listener,SOMAXCONN)){
error(Sec("listener failed ")+ std::to_string(GetLastError()));
return;
}
info(Sec("Vehicle event network online"));
do{
client = accept(Listener, nullptr, nullptr);
if(client == -1){
warn(Sec("Got an invalid client socket on connect! Skipping..."));
continue;
}
std::thread ID(Identify,client);
ID.detach();
}while(client);
closesocket(client);
WSACleanup();
}

109
src/Network/Client.cpp Normal file
View File

@@ -0,0 +1,109 @@
///
/// Created by Anonymous275 on 5/8/2020
///
#include "Client.hpp"
std::string Client::GetName(){
return Name;
}
void Client::SetName(const std::string& name){
Name = name;
}
void Client::SetDID(const std::string& did){
DID = did;
}
std::string Client::GetDID(){
return DID;
}
void Client::SetRole(const std::string& role){
Role = role;
}
std::string Client::GetRole(){
return Role;
}
int Client::GetID(){
return ID;
}
void Client::SetID(int id){
ID = id;
}
void Client::SetStatus(int state){
Status = state;
}
int Client::GetStatus(){
return Status;
}
void Client::SetUDPAddr(sockaddr_in Addr){
UDPADDR = Addr;
}
sockaddr_in Client::GetUDPAddr(){
return UDPADDR;
}
void Client::SetTCPSock(SOCKET CSock) {
TCPSOCK = CSock;
}
SOCKET Client::GetTCPSock(){
return TCPSOCK;
}
void Client::DeleteCar(int ident){
for(VData* v : VehicleData){
if(v != nullptr && v->ID == ident){
VehicleData.erase(v);
delete v;
v = nullptr;
break;
}
}
}
void Client::ClearCars(){
for(VData* v : VehicleData){
if(v != nullptr){
delete v;
v = nullptr;
}
}
VehicleData.clear();
}
int Client::GetOpenCarID(){
int OpenID = 0;
bool found;
do {
found = true;
for (VData*v : VehicleData) {
if (v != nullptr && v->ID == OpenID){
OpenID++;
found = false;
}
}
}while (!found);
return OpenID;
}
void Client::AddNewCar(int ident,const std::string& Data){
VehicleData.insert(new VData{ident,Data});
}
std::set<VData*> Client::GetAllCars(){
return VehicleData;
}
std::string Client::GetCarData(int ident){
for(VData*v : VehicleData){
if(v != nullptr && v->ID == ident){
return v->Data;
}
}
DeleteCar(ident);
return "";
}
void Client::SetCarData(int ident,const std::string&Data){
for(VData*v : VehicleData){
if(v != nullptr && v->ID == ident){
v->Data = Data;
return;
}
}
DeleteCar(ident);
}
int Client::GetCarCount(){
return int(VehicleData.size());
}

171
src/Network/GParser.cpp Normal file
View File

@@ -0,0 +1,171 @@
///
/// Created by Anonymous275 on 8/1/2020
///
#include "Lua/LuaSystem.hpp"
#include "Security/Enc.h"
#include "Client.hpp"
#include "Settings.h"
#include "Network.h"
#include "Logger.h"
int FC(const std::string& s,const std::string& p,int n) {
auto i = s.find(p);
int j;
for (j = 1; j < n && i != std::string::npos; ++j){
i = s.find(p, i+1);
}
if (j == n)return int(i);
else return -1;
}
void Apply(Client*c,int VID,const std::string& pckt){
std::string Packet = pckt;
std::string VD = c->GetCarData(VID);
Packet = Packet.substr(FC(Packet, ",", 2) + 1);
Packet = VD.substr(0, FC(VD, ",", 2) + 1) +
Packet.substr(0, Packet.find_last_of('"') + 1) +
VD.substr(FC(VD, ",\"", 7));
c->SetCarData(VID, Packet);
}
void VehicleParser(Client*c,const std::string& Pckt){
if(c == nullptr || Pckt.length() < 4)return;
std::string Packet = Pckt;
char Code = Packet.at(1);
int PID = -1;
int VID = -1;
std::string Data = Packet.substr(3),pid,vid;
switch(Code){ //Spawned Destroyed Switched/Moved NotFound Reset
case 's':
if(Data.at(0) == '0'){
int CarID = c->GetOpenCarID();
debug(c->GetName() + Sec(" created a car with ID ") + std::to_string(CarID));
Packet = "Os:"+c->GetRole()+":"+c->GetName()+":"+std::to_string(c->GetID())+"-"+std::to_string(CarID)+Packet.substr(4);
if(c->GetCarCount() >= MaxCars ||
TriggerLuaEvent(Sec("onVehicleSpawn"),false,nullptr,
new LuaArg{{c->GetID(),CarID,Packet.substr(3)}})){
Respond(c,Packet,true);
std::string Destroy = "Od:" + std::to_string(c->GetID())+"-"+std::to_string(CarID);
Respond(c,Destroy,true);
debug(c->GetName() + Sec(" (force : car limit/lua) removed ID ") + std::to_string(CarID));
}else{
c->AddNewCar(CarID,Packet);
SendToAll(nullptr, Packet,true,true);
}
}
return;
case 'c':
pid = Data.substr(0,Data.find('-'));
vid = Data.substr(Data.find('-')+1,Data.find(':',1)-Data.find('-')-1);
if(pid.find_first_not_of("0123456789") == std::string::npos && vid.find_first_not_of("0123456789") == std::string::npos){
PID = stoi(pid);
VID = stoi(vid);
}
if(PID != -1 && VID != -1 && PID == c->GetID()){
if(!TriggerLuaEvent(Sec("onVehicleEdited"),false,nullptr,
new LuaArg{{c->GetID(),VID,Packet.substr(3)}})) {
SendToAll(c, Packet, false, true);
Apply(c,VID,Packet);
}else{
std::string Destroy = "Od:" + std::to_string(c->GetID())+"-"+std::to_string(VID);
Respond(c,Destroy,true);
c->DeleteCar(VID);
}
}
return;
case 'd':
pid = Data.substr(0,Data.find('-'));
vid = Data.substr(Data.find('-')+1);
if(pid.find_first_not_of("0123456789") == std::string::npos && vid.find_first_not_of("0123456789") == std::string::npos){
PID = stoi(pid);
VID = stoi(vid);
}
if(PID != -1 && VID != -1 && PID == c->GetID()){
SendToAll(nullptr,Packet,true,true);
TriggerLuaEvent(Sec("onVehicleDeleted"),false,nullptr,
new LuaArg{{c->GetID(),VID}});
c->DeleteCar(VID);
debug(c->GetName() + Sec(" deleted car with ID ") + std::to_string(VID));
}
return;
case 'r':
SendToAll(c,Packet,false,true);
return;
default:
return;
}
}
void SyncClient(Client*c){
if(c->isSynced)return;
Respond(c,Sec("Sn")+c->GetName(),true);
SendToAll(c,Sec("JWelcome ")+c->GetName()+"!",false,true);
TriggerLuaEvent(Sec("onPlayerJoin"),false,nullptr,new LuaArg{{c->GetID()}});
for (Client*client : CI->Clients) {
if(client != nullptr){
if (client != c) {
for (VData *v : client->GetAllCars()) {
Respond(c, v->Data, true);
}
}
}
}
c->isSynced = true;
info(c->GetName() + Sec(" is now synced!"));
}
void ParseVeh(Client*c, const std::string&Packet){
__try{
VehicleParser(c,Packet);
}__except(Handle(GetExceptionInformation(),Sec("Vehicle Handler"))){}
}
void GlobalParser(Client*c, const std::string& Packet){
static int lastRecv = 0;
if(Packet.empty() || c == nullptr)return;
std::string pct;
char Code = Packet.at(0);
//V to Z
if(Code <= 90 && Code >= 86){
PPS++;
SendToAll(c,Packet,false,false);
return;
}
switch (Code) {
case 'P':
Respond(c, Sec("P") + std::to_string(c->GetID()),true);
SyncClient(c);
return;
case 'p':
Respond(c,Sec("p"),false);
UpdatePlayers();
return;
case 'O':
if(Packet.length() > 1000) {
debug(Sec("Received data from: ") + c->GetName() + Sec(" Size: ") + std::to_string(Packet.length()));
}
ParseVeh(c,Packet);
return;
case 'J':
SendToAll(c,Packet,false,true);
return;
case 'C':
if(Packet.length() < 4 || Packet.find(':', 3) == -1)break;
pct = "C:" + c->GetName() + Packet.substr(Packet.find(':', 3));
if (TriggerLuaEvent(Sec("onChatMessage"), false, nullptr,
new LuaArg{{c->GetID(), c->GetName(), pct.substr(pct.find(':', 3) + 1)}}))break;
SendToAll(nullptr, pct, true, true);
pct.clear();
return;
case 'E':
SendToAll(nullptr,Packet,true,true);
return;
default:
return;
}
}
void GParser(Client*c, const std::string&Packet){
__try{
GlobalParser(c, Packet);
}__except(Handle(GetExceptionInformation(),Sec("Global Handler"))){}
}

45
src/Network/Http.cpp Normal file
View File

@@ -0,0 +1,45 @@
///
/// Created by Anonymous275 on 4/9/2020
///
#define CURL_STATICLIB
#include "Curl/curl.h"
#include <iostream>
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp){
((std::string*)userp)->append((char*)contents, size * nmemb);
return size * nmemb;
}
std::string HttpRequest(const std::string& IP,int port){
CURL *curl;
CURLcode res;
std::string readBuffer;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str());
curl_easy_setopt(curl, CURLOPT_PORT, port);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if(res != CURLE_OK)return "-1";
}
return readBuffer;
}
std::string PostHTTP(const std::string& IP,const std::string& Fields){
CURL *curl;
CURLcode res;
std::string readBuffer;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, IP.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, Fields.size());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Fields.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
if(res != CURLE_OK)return "-1";
}
return readBuffer;
}

View File

@@ -0,0 +1,82 @@
///
/// Created by Anonymous275 on 8/1/2020
///
#include "Lua/LuaSystem.hpp"
#include "Security/Enc.h"
#include "Client.hpp"
#include "Settings.h"
#include "Network.h"
#include "Logger.h"
int OpenID(){
int ID = 0;
bool found;
do {
found = true;
for (Client *c : CI->Clients){
if(c != nullptr){
if(c->GetID() == ID){
found = false;
ID++;
}
}
}
}while (!found);
return ID;
}
void Respond(Client*c, const std::string& MSG, bool Rel){
char C = MSG.at(0);
if(Rel){
if(C == 'O' || C == 'T' || MSG.length() > 1000)SendLarge(c,MSG);
else TCPSend(c,MSG);
}else UDPSend(c,MSG);
}
void SendToAll(Client*c, const std::string& Data, bool Self, bool Rel){
char C = Data.at(0);
for(Client*client : CI->Clients){
if(client != nullptr) {
if (Self || client != c) {
if (client->isSynced) {
if (Rel) {
if (C == 'O' || C == 'T' || Data.length() > 1000)SendLarge(client, Data);
else TCPSend(client, Data);
} else UDPSend(client, Data);
}
}
}
}
}
void UpdatePlayers(){
std::string Packet = Sec("Ss") + std::to_string(CI->Size())+"/"+std::to_string(MaxPlayers) + ":";
for (Client*c : CI->Clients) {
if(c != nullptr)Packet += c->GetName() + ",";
}
Packet = Packet.substr(0,Packet.length()-1);
SendToAll(nullptr, Packet,true,true);
}
void OnDisconnect(Client*c,bool kicked){
if(c == nullptr)return;
std::string Packet;
for(VData*v : c->GetAllCars()){
if(v != nullptr) {
Packet = "Od:" + std::to_string(c->GetID()) + "-" + std::to_string(v->ID);
SendToAll(c, Packet, false, true);
}
}
if(kicked)Packet = Sec("L")+c->GetName()+Sec(" was kicked!");
Packet = Sec("L")+c->GetName()+Sec(" Left the server!");
SendToAll(c, Packet,false,true);
Packet.clear();
TriggerLuaEvent(Sec("onPlayerDisconnect"),false,nullptr,new LuaArg{{c->GetID()}});
c->ClearCars();
CI->RemoveClient(c); ///Removes the Client from existence
}
void OnConnect(Client*c){
c->SetID(OpenID());
info(Sec("Assigned ID ") + std::to_string(c->GetID()) + Sec(" to ") + c->GetName());
TriggerLuaEvent(Sec("onPlayerConnecting"),false,nullptr,new LuaArg{{c->GetID()}});
SyncResources(c);
if(c->GetStatus() < 0)return;
Respond(c,"M"+MapName,true); //Send the Map on connect
info(c->GetName() + Sec(" : Connected"));
TriggerLuaEvent(Sec("onPlayerJoining"),false,nullptr,new LuaArg{{c->GetID()}});
}

8
src/Network/NetMain.cpp Normal file
View File

@@ -0,0 +1,8 @@
#include "Network.h"
#include <thread>
ClientInterface* CI;
void NetMain(){
std::thread TCP(TCPServerMain);
TCP.detach();
UDPServerMain();
}

View File

@@ -0,0 +1,43 @@
///
/// Created by Anonymous275 on 6/18/2020
///
#include "Security/Enc.h"
#include "Client.hpp"
#include <iostream>
#include <string>
#include <thread>
std::string StatReport;
int PPS = 0;
void Monitor() {
int R, C = 0, V = 0;
if (CI->Clients.empty()){
StatReport = "-";
return;
}
for (Client *c : CI->Clients) {
if (c != nullptr && c->GetCarCount() > 0) {
C++;
V += c->GetCarCount();
}
}
if (C == 0 || PPS == 0) {
StatReport = "-";
} else {
R = (PPS / C) / V;
StatReport = std::to_string(R);
}
PPS = 0;
}
[[noreturn]]void Stat(){
while(true){
Monitor();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
void StatInit(){
StatReport = "-";
std::thread Init(Stat);
Init.detach();
}

103
src/Network/Sync.cpp Normal file
View File

@@ -0,0 +1,103 @@
///
/// Created by Anonymous275 on 8/1/2020
///
#include "Security/Enc.h"
#include "Client.hpp"
#include "Settings.h"
#include "Logger.h"
#include <fstream>
void STCPSend(Client*c,std::string Data){
if(c == nullptr)return;
int BytesSent;
BytesSent = send(c->GetTCPSock(), Data.c_str(), int(Data.size()), 0);
Data.clear();
if (BytesSent == 0){
if(c->GetStatus() > -1)c->SetStatus(-1);
}else if (BytesSent < 0) {
if(c->GetStatus() > -1)c->SetStatus(-1);
closesocket(c->GetTCPSock());
}
}
void SendFile(Client*c,const std::string&Name){
info(c->GetName()+Sec(" requesting : ")+Name.substr(Name.find_last_of('/')));
struct stat Info{};
if(stat(Name.c_str(), &Info) != 0){
STCPSend(c,Sec("Cannot Open"));
return;
}
std::ifstream f(Name.c_str(), std::ios::binary);
f.seekg(0, std::ios_base::end);
std::streampos fileSize = f.tellg();
size_t Size = fileSize,Sent = 0,Diff;
int Split = 64000;
while(c->GetStatus() > -1 && Sent < Size){
Diff = Size - Sent;
if(Diff > Split){
std::string Data(Split,0);
f.seekg(Sent, std::ios_base::beg);
f.read(&Data[0], Split);
STCPSend(c,Data);
Sent += Split;
}else{
std::string Data(Diff,0);
f.seekg(Sent, std::ios_base::beg);
f.read(&Data[0], Diff);
STCPSend(c,Data);
Sent += Diff;
}
}
f.close();
}
void Parse(Client*c,const std::string&Packet){
if(c == nullptr || Packet.empty())return;
char Code = Packet.at(0),SubCode = 0;
if(Packet.length() > 1)SubCode = Packet.at(1);
switch (Code) {
case 'f':
SendFile(c,Packet.substr(1));
return;
case 'S':
if(SubCode == 'R'){
debug(Sec("Sending Mod Info"));
std::string ToSend = FileList+FileSizes;
if(ToSend.empty())ToSend = "-";
STCPSend(c,ToSend);
}
return;
default:
return;
}
}
bool STCPRecv(Client*c){
if(c == nullptr)return false;
char buf[200];
int len = 200;
ZeroMemory(buf, len);
int BytesRcv = recv(c->GetTCPSock(), buf, len,0);
if (BytesRcv == 0){
if(c->GetStatus() > -1)c->SetStatus(-1);
closesocket(c->GetTCPSock());
return false;
}else if (BytesRcv < 0) {
if(c->GetStatus() > -1)c->SetStatus(-1);
closesocket(c->GetTCPSock());
return false;
}
if(strcmp(buf,"Done") == 0)return false;
std::string Ret(buf,BytesRcv);
Parse(c,Ret);
return true;
}
void SyncResources(Client*c){
if(c == nullptr)return;
try{
STCPSend(c,Sec("WS"));
while(c->GetStatus() > -1 && STCPRecv(c));
}catch (std::exception& e){
except(Sec("Exception! : ") + std::string(e.what()));
c->SetStatus(-1);
}
}

View File

@@ -0,0 +1,52 @@
///
/// Created by Anonymous275 on 8/1/2020
///
#include "Security/Enc.h"
#include "Network.h"
#include "Logger.h"
#include <thread>
void TCPSend(Client*c,const std::string&Data){
if(c == nullptr)return;
int BytesSent = send(c->GetTCPSock(), Data.c_str(), int(Data.length())+1, 0);
if (BytesSent == 0){
if(c->GetStatus() > -1)c->SetStatus(-1);
}else if (BytesSent < 0) {
if(c->GetStatus() > -1)c->SetStatus(-1);
closesocket(c->GetTCPSock());
}
}
void TCPRcv(Client*c){
if(c == nullptr)return;
char buf[4096];
int len = 4096;
ZeroMemory(buf, len);
int BytesRcv = recv(c->GetTCPSock(), buf, len,0);
if (BytesRcv == 0){
debug(Sec("(TCP) Connection closing..."));
if(c->GetStatus() > -1)c->SetStatus(-1);
return;
}else if (BytesRcv < 0) {
debug(Sec("(TCP) recv failed with error: ") + std::to_string(WSAGetLastError()));
if(c->GetStatus() > -1)c->SetStatus(-1);
closesocket(c->GetTCPSock());
return;
}
std::string Buf(buf,BytesRcv);
GParser(c, Buf);
}
void TCPClient(Client*c){
if(c->GetTCPSock() == -1){
CI->RemoveClient(c);
return;
}
info(Sec("Client connected"));
OnConnect(c);
while (c->GetStatus() > -1)TCPRcv(c);
info(c->GetName() + Sec(" Connection Terminated"));
OnDisconnect(c, c->GetStatus() == -2);
}
void InitClient(Client*c){
std::thread NewClient(TCPClient,c);
NewClient.detach();
}

290
src/Network/VehicleData.cpp Normal file
View File

@@ -0,0 +1,290 @@
///
/// Created by Anonymous275 on 5/8/2020
///
///UDP
#include "Security/Enc.h"
#include "Compressor.h"
#include "Client.hpp"
#include "Settings.h"
#include "Network.h"
#include "Logger.h"
#include <vector>
#include <array>
struct PacketData{
int ID;
Client* Client;
std::string Data;
int Tries;
};
struct SplitData{
int Total{};
int ID{};
std::set<std::pair<int,std::string>> Fragments;
};
SOCKET UDPSock;
std::set<PacketData*> DataAcks;
std::set<SplitData*> SplitPackets;
void UDPSend(Client*c,std::string Data){
if(c == nullptr || !c->isConnected || c->GetStatus() < 0)return;
sockaddr_in Addr = c->GetUDPAddr();
int AddrSize = sizeof(c->GetUDPAddr());
if(Data.length() > 400){
std::string CMP(Comp(Data));
Data = "ABG:" + CMP;
}
int sendOk = sendto(UDPSock, Data.c_str(), int(Data.size()), 0, (sockaddr *) &Addr, AddrSize);
if (sendOk == SOCKET_ERROR) {
debug(Sec("(UDP) Send Failed Code : ") + std::to_string(WSAGetLastError()));
if(c->GetStatus() > -1)c->SetStatus(-1);
}
}
void AckID(int ID){
for(PacketData* p : DataAcks){
if(p->ID == ID){
DataAcks.erase(p);
break;
}
}
}
int PacktID(){
static int ID = -1;
if(ID > 999999)ID = 0;
else ID++;
return ID;
}
int SplitID(){
static int SID = -1;
if(SID > 999999)SID = 0;
else SID++;
return SID;
}
void SendLarge(Client*c,const std::string&Data){
int ID = PacktID();
std::string Packet;
if(Data.length() > 1000){
std::string pckt = Data;
int S = 1,Split = int(ceil(float(pckt.length()) / 1000));
int SID = SplitID();
while(pckt.length() > 1000){
Packet = "SC"+std::to_string(S)+"/"+std::to_string(Split)+":"+std::to_string(ID)+"|"+
std::to_string(SID)+":"+pckt.substr(0,1000);
DataAcks.insert(new PacketData{ID,c,Packet,1});
UDPSend(c,Packet);
pckt = pckt.substr(1000);
S++;
ID = PacktID();
}
Packet = "SC"+std::to_string(S)+"/"+std::to_string(Split)+":"+
std::to_string(ID)+"|"+std::to_string(SID)+":"+pckt;
DataAcks.insert(new PacketData{ID,c,Packet,1});
UDPSend(c,Packet);
}else{
Packet = "BD:" + std::to_string(ID) + ":" + Data;
DataAcks.insert(new PacketData{ID,c,Packet,1});
UDPSend(c,Packet);
}
}
struct HandledC{
int Pos = 0;
Client *c{};
std::array<int, 50> HandledIDs{};
};
std::set<HandledC*> HandledIDs;
void ResetIDs(HandledC*H){
for(int C = 0;C < 50;C++){
H->HandledIDs.at(C) = -1;
}
}
HandledC*GetHandled(Client*c){
for(HandledC*h : HandledIDs){
if(h->c == c){
return h;
}
}
return new HandledC();
}
bool Handled(Client*c,int ID){
bool handle = false;
for(HandledC*h : HandledIDs){
if(h->c == c){
for(int id : h->HandledIDs){
if(id == ID)return true;
}
if(h->Pos > 49)h->Pos = 0;
h->HandledIDs.at(h->Pos) = ID;
h->Pos++;
handle = true;
}
}
for(HandledC*h : HandledIDs){
if(h->c == nullptr || !h->c->isConnected){
HandledIDs.erase(h);
break;
}
}
if(!handle){
HandledC *h = GetHandled(c);
ResetIDs(h);
if (h->Pos > 49)h->Pos = 0;
h->HandledIDs.at(h->Pos) = ID;
h->Pos++;
h->c = c;
HandledIDs.insert(h);
}
return false;
}
std::string UDPRcvFromClient(sockaddr_in& client){
char buf[10240];
int clientLength = sizeof(client);
ZeroMemory(&client, clientLength);
ZeroMemory(buf, 10240);
int Rcv = recvfrom(UDPSock, buf, 10240, 0, (sockaddr*)&client, &clientLength);
if (Rcv == -1){
error(Sec("(UDP) Error receiving from Client! Code : ") + std::to_string(WSAGetLastError()));
return "";
}
std::string Ret(Rcv,0);
memcpy_s(&Ret[0],Rcv,buf,Rcv);
return Ret;
}
SplitData*GetSplit(int SplitID){
for(SplitData* a : SplitPackets){
if(a->ID == SplitID)return a;
}
auto* SP = new SplitData();
SplitPackets.insert(SP);
return SP;
}
void HandleChunk(Client*c,const std::string&Data){
int pos1 = int(Data.find(':'))+1,
pos2 = int(Data.find(':',pos1)),
pos3 = int(Data.find('/')),
pos4 = int(Data.find('|'));
if(pos1 == std::string::npos)return;
int Max = stoi(Data.substr(pos3+1,pos1-pos3-2));
int Current = stoi(Data.substr(2,pos3-2));
int ID = stoi(Data.substr(pos1,pos4-pos1));
int SplitID = stoi(Data.substr(pos4+1,pos2-pos4-1));
std::string ack = Sec("TRG:") + Data.substr(pos1,pos4-pos1);
UDPSend(c,ack);
if(Handled(c,ID))return;
SplitData* SData = GetSplit(SplitID);
SData->Total = Max;
SData->ID = SplitID;
SData->Fragments.insert(std::make_pair(Current,Data.substr(pos2+1)));
if(SData->Fragments.size() == SData->Total){
std::string ToHandle;
for(const std::pair<int,std::string>& a : SData->Fragments){
ToHandle += a.second;
}
GParser(c,ToHandle);
SplitPackets.erase(SData);
}
}
void UDPParser(Client*c,std::string Packet){
if(Packet.substr(0,4) == Sec("ABG:")){
Packet = DeComp(Packet.substr(4));
}
if(Packet.substr(0,4) == Sec("TRG:")){
std::string pkt = Packet.substr(4);
if(Packet.find_first_not_of("0123456789") == -1){
AckID(stoi(Packet));
}
return;
}else if(Packet.substr(0,3) == Sec("BD:")){
auto pos = Packet.find(':',4);
int ID = stoi(Packet.substr(3,pos-3));
std::string pkt = Sec("TRG:") + std::to_string(ID);
UDPSend(c,pkt);
if(!Handled(c,ID)) {
pkt = Packet.substr(pos + 1);
GParser(c, pkt);
}
return;
}else if(Packet.substr(0,2) == Sec("SC")){
HandleChunk(c,Packet);
return;
}
GParser(c,Packet);
}
#include <thread>
void StartLoop();
[[noreturn]] void UDPServerMain(){
WSADATA data;
if (WSAStartup(514, &data)){
error(Sec("Can't start Winsock!"));
//return;
}
UDPSock = socket(AF_INET, SOCK_DGRAM, 0);
// Create a server hint structure for the server
sockaddr_in serverAddr{};
serverAddr.sin_addr.S_un.S_addr = ADDR_ANY; //Any Local
serverAddr.sin_family = AF_INET; // Address format is IPv4
serverAddr.sin_port = htons(Port); // Convert from little to big endian
// Try and bind the socket to the IP and port
if (bind(UDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR){
error(Sec("Can't bind socket!") + std::to_string(WSAGetLastError()));
std::this_thread::sleep_for(std::chrono::seconds(5));
exit(-1);
//return;
}
DataAcks.clear();
StartLoop();
info(Sec("Vehicle data network online on port ")+std::to_string(Port)+Sec(" with a Max of ")+std::to_string(MaxPlayers)+Sec(" Clients"));
while (true){
sockaddr_in client{};
std::string Data = UDPRcvFromClient(client); //Receives any data from Socket
auto Pos = Data.find(':');
if(Data.empty() || Pos < 0 || Pos > 2)continue;
/*char clientIp[256];
ZeroMemory(clientIp, 256); ///Code to get IP we don't need that yet
inet_ntop(AF_INET, &client.sin_addr, clientIp, 256);*/
uint8_t ID = Data.at(0)-1;
for(Client*c : CI->Clients){
if(c != nullptr && c->GetID() == ID){
c->SetUDPAddr(client);
c->isConnected = true;
std::thread Parse(UDPParser,c,Data.substr(2));
Parse.detach();
}
}
}
/*closesocket(UDPSock);
WSACleanup();
return;*/
}
void LOOP(){
while(UDPSock != -1) {
for (PacketData* p : DataAcks){
if(p != nullptr) {
if (p->Client == nullptr || p->Client->GetTCPSock() == -1) {
DataAcks.erase(p);
break;
}
if (p->Tries < 20) {
UDPSend(p->Client, p->Data);
p->Tries++;
} else {
DataAcks.erase(p);
delete p;
p = nullptr;
break;
}
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
}
void StartLoop(){
std::thread Ack(LOOP);
Ack.detach();
}