mirror of
https://github.com/BeamMP/BeamMP-Server.git
synced 2026-04-08 08:46:04 +00:00
V0.6
rewrite
This commit is contained in:
172
src/Network/Auth.cpp
Normal file
172
src/Network/Auth.cpp
Normal 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
109
src/Network/Client.cpp
Normal 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
171
src/Network/GParser.cpp
Normal 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
45
src/Network/Http.cpp
Normal 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;
|
||||
}
|
||||
82
src/Network/InitClient.cpp
Normal file
82
src/Network/InitClient.cpp
Normal 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
8
src/Network/NetMain.cpp
Normal file
@@ -0,0 +1,8 @@
|
||||
#include "Network.h"
|
||||
#include <thread>
|
||||
ClientInterface* CI;
|
||||
void NetMain(){
|
||||
std::thread TCP(TCPServerMain);
|
||||
TCP.detach();
|
||||
UDPServerMain();
|
||||
}
|
||||
43
src/Network/StatMonitor.cpp
Normal file
43
src/Network/StatMonitor.cpp
Normal 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
103
src/Network/Sync.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
52
src/Network/TCPHandler.cpp
Normal file
52
src/Network/TCPHandler.cpp
Normal 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
290
src/Network/VehicleData.cpp
Normal 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();
|
||||
}
|
||||
Reference in New Issue
Block a user