diff --git a/src/Network 2.0/ClientInterface.cpp b/src/Network 2.0/ClientInterface.cpp index e0b9a04..7f87183 100644 --- a/src/Network 2.0/ClientInterface.cpp +++ b/src/Network 2.0/ClientInterface.cpp @@ -23,20 +23,21 @@ int OpenID(){ }while (!found); return ID; } -void TCPSendLarge(Client*c,const std::string&Data); +void SendLarge(Client*c,const std::string&Data); void Respond(Client*c, const std::string& MSG, bool Rel){ + char C = MSG.at(0); if(Rel){ - if(MSG.length() > 1000)TCPSendLarge(c,MSG); + if(C == 'O' || C == 'T' || MSG.length() > 1000)SendLarge(c,MSG); else TCPSend(c,MSG); - } - else UDPSend(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 : Clients){ if(Self || client != c){ if(Rel){ - if(Data.length() > 1000 || Data.substr(0,2) == "Od")TCPSendLarge(client,Data); + if(C == 'O' || C == 'T' || Data.length() > 1000)SendLarge(client,Data); else TCPSend(client,Data); } else UDPSend(client,Data); @@ -55,17 +56,15 @@ void UpdatePlayers(){ void OnDisconnect(Client*c,bool kicked){ std::string Packet; - for(const std::pair&a : c->GetAllCars()){ Packet = "Od:" + std::to_string(c->GetID()) + "-" + std::to_string(a.first); SendToAll(c, Packet,false,true); } - if(kicked)Packet = "L"+c->GetName()+" was kicked!"; Packet = "L"+c->GetName()+" Left the server!"; SendToAll(c, Packet,false,true); Packet.clear(); - Clients.erase(c); ///Removes the Client from the existence + Clients.erase(c); ///Removes the Client from existence } int TriggerLuaEvent(const std::string& Event,bool local,Lua*Caller); void OnConnect(Client*c){ diff --git a/src/Network 2.0/DataParser.cpp b/src/Network 2.0/DataParser.cpp index a92f567..bac24b9 100644 --- a/src/Network 2.0/DataParser.cpp +++ b/src/Network 2.0/DataParser.cpp @@ -14,17 +14,6 @@ void Respond(Client*c, const std::string& MSG, bool Rel); void UpdatePlayers(); - -/*void FindAndSync(Client*c,int ClientID){ - for (Client*client : Clients) { - if (client != c){ - if(client->GetID() == ClientID){ /////mark - Respond(client,c->GetCarData(ClientID),true); - } - } - } -}*/ - int TriggerLuaEvent(const std::string& Event,bool local,Lua*Caller); void VehicleParser(Client*c, std::string Packet){ char Code = Packet.at(1); @@ -62,12 +51,6 @@ void VehicleParser(Client*c, std::string Packet){ break; case 'm': break; - /*case 'n': - if(Packet.substr(3).find_first_not_of("0123456789") == std::string::npos){ - PID = stoi(Packet.substr(3)); - } - FindAndSync(c,PID); //ACK System - break;*/ case 'r': SendToAll(c,Packet,false,true); break; diff --git a/src/Network 2.0/VehicleData.cpp b/src/Network 2.0/VehicleData.cpp index 7b8607d..c472488 100644 --- a/src/Network 2.0/VehicleData.cpp +++ b/src/Network 2.0/VehicleData.cpp @@ -6,13 +6,25 @@ #include "Client.hpp" #include #include -#include +#include #include "../logger.h" #include "../Settings.hpp" -SOCKET UDPSock; +struct PacketData{ + int ID; + Client* Client; + std::string Data; + int Tries; +}; +struct SplitData{ + int Total; + int ID; + std::set> Fragments; +}; -std::set> BigDataAcks; +SOCKET UDPSock; +std::set DataAcks; +std::set SplitPackets; void UDPSend(Client*c,const std::string&Data){ if(!c->isConnected())return; sockaddr_in Addr = c->GetUDPAddr(); @@ -22,22 +34,103 @@ void UDPSend(Client*c,const std::string&Data){ } void AckID(int ID){ - for(std::tuple a : BigDataAcks){ - if(get<0>(a) == ID){ - BigDataAcks.erase(a); + for(PacketData* p : DataAcks){ + if(p->ID == ID){ + DataAcks.erase(p); break; } } } - -void TCPSendLarge(Client*c,const std::string&Data){ - static int ID = 0; - std::string Header = "BD:" + std::to_string(ID) + ":"; - BigDataAcks.insert(std::make_tuple(ID,c,Header+Data)); - if(ID > 483647)ID = 0; +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 = 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 HandledIDs; +}; +std::set 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); @@ -52,7 +145,39 @@ std::string UDPRcvFromClient(sockaddr_in& client){ return std::string(buf); } +SplitData*GetSplit(int SplitID){ + for(SplitData* a : SplitPackets){ + if(a->ID == SplitID)return a; + } + SplitData* a = new SplitData(); + SplitPackets.insert(a); + return a; +} + void GlobalParser(Client*c, const std::string&Packet); +void HandleChunk(Client*c,const std::string&Data){ + int pos1 = Data.find(':')+1,pos2 = Data.find(':',pos1),pos3 = Data.find('/'); + int pos4 = Data.find('|'); + 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 = "ACK:" + 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(std::pair a : SData->Fragments){ + ToHandle += a.second; + } + GlobalParser(c,ToHandle); + SplitPackets.erase(SData); + } +} void UDPParser(Client*c, const std::string&Packet){ if(Packet.substr(0,4) == "ACK:"){ @@ -61,10 +186,16 @@ void UDPParser(Client*c, const std::string&Packet){ return; }else if(Packet.substr(0,3) == "BD:"){ int pos = Packet.find(':',4); - std::string pckt = "ACK:" + Packet.substr(3,pos-3); + int ID = stoi(Packet.substr(3,pos-3)); + std::string pckt = "ACK:" + std::to_string(ID); UDPSend(c,pckt); - pckt = Packet.substr(pos+1); - GlobalParser(c,pckt); + if(!Handled(c,ID)) { + pckt = Packet.substr(pos + 1); + GlobalParser(c, pckt); + } + return; + }else if(Packet.substr(0,2) == "SC"){ + HandleChunk(c,Packet); return; } GlobalParser(c,Packet); @@ -96,7 +227,7 @@ void StartLoop(); //return; } - BigDataAcks.clear(); + DataAcks.clear(); StartLoop(); info("Vehicle data network online on port "+std::to_string(Port)+" with a Max of "+std::to_string(MaxPlayers)+" Clients"); @@ -109,7 +240,6 @@ void StartLoop(); /*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 : Clients){ if(c->GetID() == ID){ @@ -127,14 +257,20 @@ void StartLoop(); #include void LOOP(){ while(UDPSock != -1) { - for (std::tuple a : BigDataAcks) { - if (get<1>(a)->GetTCPSock() == -1) { - BigDataAcks.erase(a); + for (PacketData* p : DataAcks){ + 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); break; } - UDPSend(get<1>(a), get<2>(a)); } - std::this_thread::sleep_for(std::chrono::seconds(2)); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); } } void StartLoop(){ diff --git a/src/Settings.hpp b/src/Settings.hpp index 4505a35..e4bd30c 100644 --- a/src/Settings.hpp +++ b/src/Settings.hpp @@ -15,3 +15,4 @@ extern std::string ClientVersion; extern std::string FileList; extern std::string FileSizes; extern std::string Key; +extern std::string CustomIP; diff --git a/src/config.cpp b/src/config.cpp index 90626cc..9075da3 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -6,7 +6,7 @@ #include #include #include "logger.h" -using namespace std; //nameSpace STD + void GenerateConfig(); string RemoveComments(const string& Line); void SetValues(const string& Line, int Index); diff --git a/src/heartbeat.cpp b/src/heartbeat.cpp index 3ab9374..d839374 100644 --- a/src/heartbeat.cpp +++ b/src/heartbeat.cpp @@ -9,8 +9,6 @@ #include "Settings.hpp" #include "Network 2.0/Client.hpp" -using namespace std; - string HTTP_REQUEST(const std::string&,int); std::string PostHTTP(const std::string& IP,const std::string& Fields); std::string HTA(const std::string& hex) @@ -34,6 +32,7 @@ void Heartbeat() R = "uuid="+Key+"&players="+to_string(Clients.size())+"&maxplayers="+to_string(MaxPlayers)+"&port=" + to_string(Port) + "&map=" + MapName + "&private="+State+"&version="+ServerVersion+ "&clientversion="+ClientVersion+"&name="+ServerName; + if(!CustomIP.empty())R+="&ip="+CustomIP; // https://beamng-mp.com/heartbeatv2 R = PostHTTP(HTA("68747470733a2f2f6265616d6e672d6d702e636f6d2f6865617274626561747632"),R); if(R.find_first_not_of("20") != std::string::npos){ diff --git a/src/http.cpp b/src/http.cpp index f413f2c..2b9b5fc 100644 --- a/src/http.cpp +++ b/src/http.cpp @@ -6,8 +6,6 @@ #include "curl/curl.h" #include -#include - static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { @@ -42,6 +40,7 @@ std::string PostHTTP(const std::string& IP,const std::string& Fields){ 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); } diff --git a/src/main.cpp b/src/main.cpp index e98a6ec..26778a6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,22 +8,32 @@ #include #include #include "logger.h" +#include #include "Settings.hpp" -using namespace std; void DebugData(); void LogInit(); void ParseConfig(); void addToLog(const string& Data); //void ServerMain(int Port, int MaxClients); void HeartbeatInit(); -string ServerVersion = "0.2"; -string ClientVersion = "1.1+"; +std::string ServerVersion = "0.2"; +std::string ClientVersion = "1.1+"; +std::string CustomIP; void HandleResources(std::string path); //void TCPMain(int Port); void NetMain(); //Entry -int main() { +int main(int argc, char* argv[]) { + if(argc > 1){ + CustomIP = argv[1]; + size_t n = std::count(CustomIP.begin(), CustomIP.end(), '.'); + int p = CustomIP.find_first_not_of(".0123456789"); + if(p != std::string::npos || n != 3 || CustomIP.substr(0,3) == "127"){ + CustomIP.clear(); + warn("IP Specified is invalid!"); + }else info("Started with custom ip : " + CustomIP); + } LogInit(); ParseConfig(); info("BeamMP Server Running version " + ServerVersion);