Server update 0.63.5

- async lua implementation
- cleaner backend heartbeat
- two way encryption on connect
- async tcp buffer
- disconnect handler
- cleaned UDP implementation
This commit is contained in:
Anonymous275
2020-10-16 17:05:31 +03:00
parent 31c96cee94
commit 71a84b4f1b
14 changed files with 314 additions and 169 deletions

View File

@@ -29,8 +29,10 @@ std::string Rcv(SOCKET TCPSock){
}
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()){
std::string a = HttpRequest(Sec("https://beammp.com/entitlement?did=")+DID,443);
std::string b = HttpRequest(Sec("https://backup1.beammp.com/entitlement?did=")+DID,443);
if(!a.empty() || !b.empty()){
if(a != b)a = b;
auto pos = a.find('"');
if(pos != std::string::npos){
return a.substr(pos+1,a.find('"',pos+1)-2);
@@ -63,26 +65,46 @@ void CreateClient(SOCKET TCPSock,const std::string &Name, const std::string &DID
CI->AddClient(c);
InitClient(c);
}
std::pair<int,int> Parse(const std::string& msg){
std::stringstream ss(msg);
std::string t;
std::pair<int,int> a = {0,0}; //N then E
while (std::getline(ss, t, 'g')) {
if(t.find_first_not_of(Sec("0123456789abcdef")) != std::string::npos)return a;
if(a.first == 0){
a.first = std::stoi(t, nullptr, 16);
}else if(a.second == 0){
a.second = std::stoi(t, nullptr, 16);
}else return a;
}
return {0,0};
}
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){
void Identification(SOCKET TCPSock,Hold*S,RSA*Skey){
S->TCPSock = TCPSock;
std::thread Timeout(Check,S);
Timeout.detach();
std::string Name,DID,Role;
if(!Send(TCPSock,GenerateM(key))){
if(!Send(TCPSock,GenerateM(Skey))){
closesocket(TCPSock);
return;
}
std::string msg = Rcv(TCPSock);
auto Keys = Parse(msg);
if(!Send(TCPSock,RSA_E("HC",Keys.second,Keys.first))){
closesocket(TCPSock);
return;
}
std::string Res = Rcv(TCPSock);
std::string Ver = Rcv(TCPSock);
S->Done = true;
Ver = RSA_D(Ver,key);
Ver = RSA_D(Ver,Skey);
if(Ver.size() > 3 && Ver.substr(0,2) == Sec("VC")){
Ver = Ver.substr(2);
if(Ver.length() > 4 || Ver != GetCVer()){
@@ -93,7 +115,7 @@ void Identification(SOCKET TCPSock,Hold*S,RSA*key){
closesocket(TCPSock);
return;
}
Res = RSA_D(Res,key);
Res = RSA_D(Res,Skey);
if(Res.size() < 3 || Res.substr(0,2) != Sec("NR")) {
closesocket(TCPSock);
return;
@@ -125,11 +147,15 @@ void Identification(SOCKET TCPSock,Hold*S,RSA*key){
}
void Identify(SOCKET TCPSock){
auto* S = new Hold;
RSA*key = GenKey();
RSA*Skey = GenKey();
__try{
Identification(TCPSock,S,key);
}__except(1){}
delete key;
Identification(TCPSock,S,Skey);
}__except(1){
if(TCPSock != -1){
closesocket(TCPSock);
}
}
delete Skey;
delete S;
}
void TCPServerMain(){

View File

@@ -7,6 +7,7 @@
#include "Settings.h"
#include "Network.h"
#include "Logger.h"
#include <sstream>
int FC(const std::string& s,const std::string& p,int n) {
auto i = s.find(p);
@@ -42,7 +43,7 @@ void VehicleParser(Client*c,const std::string& Pckt){
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)}})){
new LuaArg{{c->GetID(),CarID,Packet.substr(3)}},true)){
Respond(c,Packet,true);
std::string Destroy = "Od:" + std::to_string(c->GetID())+"-"+std::to_string(CarID);
Respond(c,Destroy,true);
@@ -62,7 +63,7 @@ void VehicleParser(Client*c,const std::string& Pckt){
}
if(PID != -1 && VID != -1 && PID == c->GetID()){
if(!TriggerLuaEvent(Sec("onVehicleEdited"),false,nullptr,
new LuaArg{{c->GetID(),VID,Packet.substr(3)}})) {
new LuaArg{{c->GetID(),VID,Packet.substr(3)}},true)) {
SendToAll(c, Packet, false, true);
Apply(c,VID,Packet);
}else{
@@ -82,7 +83,7 @@ void VehicleParser(Client*c,const std::string& Pckt){
if(PID != -1 && VID != -1 && PID == c->GetID()){
SendToAll(nullptr,Packet,true,true);
TriggerLuaEvent(Sec("onVehicleDeleted"),false,nullptr,
new LuaArg{{c->GetID(),VID}});
new LuaArg{{c->GetID(),VID}},false);
c->DeleteCar(VID);
debug(c->GetName() + Sec(" deleted car with ID ") + std::to_string(VID));
}
@@ -96,19 +97,23 @@ void VehicleParser(Client*c,const std::string& Pckt){
}
void SyncClient(Client*c){
if(c->isSynced)return;
c->isSynced = true;
std::this_thread::sleep_for(std::chrono::seconds(1));
Respond(c,Sec("Sn")+c->GetName(),true);
SendToAll(c,Sec("JWelcome ")+c->GetName()+"!",false,true);
TriggerLuaEvent(Sec("onPlayerJoin"),false,nullptr,new LuaArg{{c->GetID()}});
TriggerLuaEvent(Sec("onPlayerJoin"),false,nullptr,new LuaArg{{c->GetID()}},false);
for (Client*client : CI->Clients) {
if(client != nullptr){
if (client != c) {
for (VData *v : client->GetAllCars()) {
Respond(c, v->Data, true);
if(v != nullptr){
Respond(c, v->Data, true);
std::this_thread::sleep_for(std::chrono::seconds(2));
}
}
}
}
}
c->isSynced = true;
info(c->GetName() + Sec(" is now synced!"));
}
void ParseVeh(Client*c, const std::string&Packet){
@@ -117,9 +122,30 @@ void ParseVeh(Client*c, const std::string&Packet){
}__except(Handle(GetExceptionInformation(),Sec("Vehicle Handler"))){}
}
void GlobalParser(Client*c, const std::string& Packet){
void HandleEvent(Client*c ,const std::string&Data){
std::stringstream ss(Data);
std::string t,Name;
int a = 0;
while (std::getline(ss, t, ':')) {
switch(a){
case 1:
Name = t;
break;
case 2:
TriggerLuaEvent(Name, false, nullptr,new LuaArg{{c->GetID(),t}},false);
break;
default:
break;
}
if(a == 2)break;
a++;
}
}
void GlobalParser(Client*c, const std::string& Pack){
static int lastRecv = 0;
if(Packet.empty() || c == nullptr)return;
if(Pack.empty() || c == nullptr)return;
std::string Packet = Pack.substr(0,Pack.find(char(0)));
std::string pct;
char Code = Packet.at(0);
@@ -150,14 +176,13 @@ void GlobalParser(Client*c, const std::string& Packet){
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();
if (TriggerLuaEvent(Sec("onChatMessage"), false, nullptr,new LuaArg{
{c->GetID(), c->GetName(), Packet.substr(Packet.find(':', 3) + 1)}
},true))break;
SendToAll(nullptr, Packet, true, true);
return;
case 'E':
SendToAll(nullptr,Packet,true,true);
HandleEvent(c,Packet);
return;
default:
return;

View File

@@ -25,7 +25,7 @@ int OpenID(){
}
void Respond(Client*c, const std::string& MSG, bool Rel){
char C = MSG.at(0);
if(Rel){
if(Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E'){
if(C == 'O' || C == 'T' || MSG.length() > 1000)SendLarge(c,MSG);
else TCPSend(c,MSG);
}else UDPSend(c,MSG);
@@ -35,9 +35,10 @@ void SendToAll(Client*c, const std::string& Data, bool Self, bool Rel){
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);
if (client->isSynced || (C == 'O' && Data.at(1) == 's')) {
if (Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E') {
if (C == 'O' || C == 'T' ||
Data.length() > 1000)SendLarge(client, Data);
else TCPSend(client, Data);
} else UDPSend(client, Data);
}
@@ -54,6 +55,7 @@ void UpdatePlayers(){
SendToAll(nullptr, Packet,true,true);
}
void OnDisconnect(Client*c,bool kicked){
info(c->GetName() + Sec(" Connection Terminated"));
if(c == nullptr)return;
std::string Packet;
for(VData*v : c->GetAllCars()){
@@ -66,17 +68,18 @@ void OnDisconnect(Client*c,bool 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()}});
TriggerLuaEvent(Sec("onPlayerDisconnect"),false,nullptr,new LuaArg{{c->GetID()}},false);
c->ClearCars();
CI->RemoveClient(c); ///Removes the Client from existence
}
void OnConnect(Client*c){
info(Sec("Client connected"));
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()}});
TriggerLuaEvent(Sec("onPlayerConnecting"),false,nullptr,new LuaArg{{c->GetID()}},false);
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()}});
TriggerLuaEvent(Sec("onPlayerJoining"),false,nullptr,new LuaArg{{c->GetID()}},false);
}

View File

@@ -8,16 +8,24 @@
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){
std::string Send = "\n" + Data.substr(0,Data.find(char(0))) + "\n";
size_t Sent = send(c->GetTCPSock(), Send.c_str(), int(Send.size()), 0);
if (Sent == 0){
if(c->GetStatus() > -1)c->SetStatus(-1);
}else if (BytesSent < 0) {
}else if (Sent < 0) {
if(c->GetStatus() > -1)c->SetStatus(-1);
closesocket(c->GetTCPSock());
}
}
void TCPHandle(Client*c,const std::string& data){
__try{
c->Handler.Handle(c,data);
}__except(1){
c->Handler.clear();
}
}
void TCPRcv(Client*c){
if(c == nullptr)return;
if(c == nullptr || c->GetStatus() < 0)return;
char buf[4096];
int len = 4096;
ZeroMemory(buf, len);
@@ -33,18 +41,18 @@ void TCPRcv(Client*c){
return;
}
std::string Buf(buf,BytesRcv);
GParser(c, Buf);
TCPHandle(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);
__try{
OnDisconnect(c, c->GetStatus() == -2);
}__except(Handle(GetExceptionInformation(),Sec("OnDisconnect"))){}
}
void InitClient(Client*c){
std::thread NewClient(TCPClient,c);

View File

@@ -8,9 +8,11 @@
#include "Settings.h"
#include "Network.h"
#include "Logger.h"
#include <sstream>
#include <vector>
#include <thread>
#include <array>
int FC(const std::string& s,const std::string& p,int n);
struct PacketData{
int ID;
Client* Client;
@@ -30,11 +32,11 @@ 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());
Data = Data.substr(0,Data.find(char(0)));
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()));
@@ -44,7 +46,7 @@ void UDPSend(Client*c,std::string Data){
void AckID(int ID){
for(PacketData* p : DataAcks){
if(p->ID == ID){
if(p != nullptr && p->ID == ID){
DataAcks.erase(p);
break;
}
@@ -62,7 +64,8 @@ int SplitID(){
else SID++;
return SID;
}
void SendLarge(Client*c,const std::string&Data){
void SendLarge(Client*c,std::string Data){
Data = Data.substr(0,Data.find(char(0)));
int ID = PacktID();
std::string Packet;
if(Data.length() > 1000){
@@ -70,16 +73,16 @@ void SendLarge(Client*c,const std::string&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);
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;
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{
@@ -90,12 +93,12 @@ void SendLarge(Client*c,const std::string&Data){
}
struct HandledC{
int Pos = 0;
Client *c{};
std::array<int, 50> HandledIDs{};
Client *c = nullptr;
std::array<int, 100> HandledIDs = {-1};
};
std::set<HandledC*> HandledIDs;
void ResetIDs(HandledC*H){
for(int C = 0;C < 50;C++){
for(int C = 0;C < 100;C++){
H->HandledIDs.at(C) = -1;
}
}
@@ -114,7 +117,7 @@ bool Handled(Client*c,int ID){
for(int id : h->HandledIDs){
if(id == ID)return true;
}
if(h->Pos > 49)h->Pos = 0;
if(h->Pos > 99)h->Pos = 0;
h->HandledIDs.at(h->Pos) = ID;
h->Pos++;
handle = true;
@@ -129,7 +132,7 @@ bool Handled(Client*c,int ID){
if(!handle){
HandledC *h = GetHandled(c);
ResetIDs(h);
if (h->Pos > 49)h->Pos = 0;
if (h->Pos > 99)h->Pos = 0;
h->HandledIDs.at(h->Pos) = ID;
h->Pos++;
h->c = c;
@@ -138,17 +141,14 @@ bool Handled(Client*c,int ID){
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);
std::string Ret(10240,0);
int Rcv = recvfrom(UDPSock, &Ret[0], 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;
}
@@ -161,22 +161,27 @@ SplitData*GetSplit(int SplitID){
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);
int pos = FC(Data,"|",5);
if(pos == -1)return;
std::stringstream ss(Data.substr(0,pos++));
std::string t;
int I = -1;
//Current Max ID SID
std::vector<int> Num(4,0);
while (std::getline(ss, t, '|')) {
if(I != -1)Num.at(I) = std::stoi(t);
I++;
}
std::string ack = "TRG:" + std::to_string(Num.at(2));
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(Handled(c,Num.at(2))){
return;
}
std::string Packet = Data.substr(pos);
SplitData* SData = GetSplit(Num.at(3));
SData->Total = Num.at(1);
SData->ID = Num.at(3);
SData->Fragments.insert(std::make_pair(Num.at(0),Packet));
if(SData->Fragments.size() == SData->Total){
std::string ToHandle;
for(const std::pair<int,std::string>& a : SData->Fragments){
@@ -184,36 +189,56 @@ void HandleChunk(Client*c,const std::string&Data){
}
GParser(c,ToHandle);
SplitPackets.erase(SData);
delete SData;
SData = nullptr;
}
}
void UDPParser(Client*c,std::string Packet){
if(Packet.substr(0,4) == Sec("ABG:")){
if(Packet.substr(0,4) == "ABG:"){
Packet = DeComp(Packet.substr(4));
}
if(Packet.substr(0,4) == Sec("TRG:")){
if(Packet.substr(0,4) == "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:")){
}else if(Packet.substr(0,3) == "BD:"){
auto pos = Packet.find(':',4);
int ID = stoi(Packet.substr(3,pos-3));
std::string pkt = Sec("TRG:") + std::to_string(ID);
std::string pkt = "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")){
}else if(Packet.substr(0,2) == "SC"){
HandleChunk(c,Packet);
return;
}
GParser(c,Packet);
}
#include <thread>
void StartLoop();
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 < 15) {
UDPSend(p->Client, p->Data);
p->Tries++;
} else {
DataAcks.erase(p);
break;
}
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
}
[[noreturn]] void UDPServerMain(){
WSADATA data;
if (WSAStartup(514, &data)){
@@ -237,7 +262,8 @@ void StartLoop();
}
DataAcks.clear();
StartLoop();
std::thread Ack(LOOP);
Ack.detach();
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){
@@ -253,38 +279,11 @@ void StartLoop();
if(c != nullptr && c->GetID() == ID){
c->SetUDPAddr(client);
c->isConnected = true;
std::thread Parse(UDPParser,c,Data.substr(2));
Parse.detach();
UDPParser(c,Data.substr(2));
}
}
}
/*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();
}
}