From 40cae31885e40cbdafa72a9d382c8f30a6602f8c Mon Sep 17 00:00:00 2001 From: Lion Kortlepel Date: Mon, 8 Mar 2021 23:45:25 +0100 Subject: [PATCH] Merge TUDPServer and TTCPServer into TNetwork this gets rid of a bunch of unclear cases which I mistakenly created while refactoring for this rewrite. One example is having to call into TTCPServer to do UDP sending in some cases. --- CMakeLists.txt | 5 +- include/TConfig.h | 2 +- include/TLuaEngine.h | 13 +- include/{TTCPServer.h => TNetwork.h} | 34 +-- include/TPPSMonitor.h | 11 +- include/TServer.h | 7 +- include/TUDPServer.h | 28 -- src/Common.cpp | 1 + src/TLuaEngine.cpp | 8 +- src/TLuaFile.cpp | 39 +-- src/{TTCPServer.cpp => TNetwork.cpp} | 435 ++++++++++++++++++--------- src/TPPSMonitor.cpp | 6 +- src/TServer.cpp | 47 ++- src/TUDPServer.cpp | 182 ----------- src/main.cpp | 11 +- 15 files changed, 378 insertions(+), 451 deletions(-) rename include/{TTCPServer.h => TNetwork.h} (73%) delete mode 100644 include/TUDPServer.h rename src/{TTCPServer.cpp => TNetwork.cpp} (70%) delete mode 100644 src/TUDPServer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 323903c..55cfb93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ elseif (UNIX) message(STATUS "sanitize is ON") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined,thread") endif (SANITIZE) -endif() +endif () # this has to happen before -DDEBUG since it wont compile properly with -DDEBUG include_directories("asio/asio/include") @@ -44,8 +44,7 @@ add_executable(BeamMP-Server include/Http.h src/Http.cpp include/SocketIO.h src/SocketIO.cpp include/TPPSMonitor.h src/TPPSMonitor.cpp - include/TUDPServer.h src/TUDPServer.cpp - include/TTCPServer.h src/TTCPServer.cpp) + include/TNetwork.h src/TNetwork.cpp) target_include_directories(BeamMP-Server PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/commandline") diff --git a/include/TConfig.h b/include/TConfig.h index 2e78bf3..725ac61 100644 --- a/include/TConfig.h +++ b/include/TConfig.h @@ -4,7 +4,7 @@ class TConfig { public: - TConfig(const std::string& ConfigFile); + explicit TConfig(const std::string& ConfigFile); private: static std::string RemoveComments(const std::string& Line); diff --git a/include/TLuaEngine.h b/include/TLuaEngine.h index f77341f..9e59964 100644 --- a/include/TLuaEngine.h +++ b/include/TLuaEngine.h @@ -4,15 +4,14 @@ #include "IThreaded.h" #include "TLuaFile.h" #include "TServer.h" -#include #include #include +#include #include class TLuaEngine : public IThreaded { public: - explicit TLuaEngine(TServer& Server, TTCPServer& TCPServer, TUDPServer& UDPServer); - //~TLuaEngine(); + explicit TLuaEngine(TServer& Server, TNetwork& Network); using TSetOfLuaFile = std::set>; @@ -21,19 +20,17 @@ public: [[nodiscard]] const TSetOfLuaFile& LuaFiles() const { return mLuaFiles; } [[nodiscard]] TServer& Server() { return mServer; } [[nodiscard]] const TServer& Server() const { return mServer; } + [[nodiscard]] TNetwork& Network() { return mNetwork; } + [[nodiscard]] const TNetwork& Network() const { return mNetwork; } std::optional> GetScript(lua_State* L); - TTCPServer& TCPServer() { return mTCPServer; } - TUDPServer& UDPServer() { return mUDPServer; } - private: void FolderList(const std::string& Path, bool HotSwap); void RegisterFiles(const std::string& Path, bool HotSwap); bool NewFile(const std::string& Path); - TTCPServer& mTCPServer; - TUDPServer& mUDPServer; + TNetwork& mNetwork; TServer& mServer; std::string mPath; bool mShutdown { false }; diff --git a/include/TTCPServer.h b/include/TNetwork.h similarity index 73% rename from include/TTCPServer.h rename to include/TNetwork.h index d0307a6..f1a7a70 100644 --- a/include/TTCPServer.h +++ b/include/TNetwork.h @@ -1,20 +1,12 @@ #pragma once -#include "Client.h" -#include "Common.h" #include "Compat.h" -#include "IThreaded.h" +#include "TResourceManager.h" #include "TServer.h" -#include -class TResourceManager; - -class TTCPServer : public IThreaded { +class TNetwork { public: - explicit TTCPServer(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager); - //~TTCPServer(); - - void operator()() override; + TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager); bool TCPSend(TClient& c, const std::string& Data, bool IsSync = false); void SendLarge(TClient& c, std::string Data, bool isSync = false); @@ -22,26 +14,28 @@ public: std::shared_ptr CreateClient(SOCKET TCPSock); std::string TCPRcv(TClient& c); void ClientKick(TClient& c, const std::string& R); - - void SetUDPServer(TUDPServer& UDPServer); - - TUDPServer& UDPServer() { return mUDPServer->get(); } - void SyncClient(const std::weak_ptr& c); void Identify(SOCKET TCPSock); void Authentication(SOCKET TCPSock); bool CheckBytes(TClient& c, int32_t BytesRcv); void SyncResources(TClient& c); - + void UDPSend(TClient& Client, std::string Data) const; + void SendToAll(TClient* c, const std::string& Data, bool Self, bool Rel); void UpdatePlayer(TClient& Client); private: - std::optional> mUDPServer { std::nullopt }; + void UDPServerMain(); + void TCPServerMain(); + TServer& mServer; TPPSMonitor& mPPSMonitor; - TResourceManager& mResourceManager; + SOCKET mUDPSock {}; bool mShutdown { false }; + TResourceManager& mResourceManager; + std::thread mUDPThread; + std::thread mTCPThread; + std::string UDPRcvFromClient(sockaddr_in& client) const; void HandleDownload(SOCKET TCPSock); void OnConnect(const std::weak_ptr& c); void TCPClient(const std::weak_ptr& c); @@ -51,4 +45,4 @@ private: void SendFile(TClient& c, const std::string& Name); static bool TCPSendRaw(SOCKET C, char* Data, int32_t Size); static void SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std::string& Name); -}; \ No newline at end of file +}; diff --git a/include/TPPSMonitor.h b/include/TPPSMonitor.h index 43b5759..508dfc5 100644 --- a/include/TPPSMonitor.h +++ b/include/TPPSMonitor.h @@ -3,6 +3,9 @@ #include "Common.h" #include "TServer.h" #include + +class TNetwork; + class TPPSMonitor : public IThreaded { public: explicit TPPSMonitor(TServer& Server); @@ -12,13 +15,13 @@ public: void SetInternalPPS(int NewPPS) { mInternalPPS = NewPPS; } void IncrementInternalPPS() { ++mInternalPPS; } [[nodiscard]] int InternalPPS() const { return mInternalPPS; } - void SetTCPServer(TTCPServer& Server) { mTCPServer = std::ref(Server); } + void SetNetwork(TNetwork& Server) { mNetwork = std::ref(Server); } private: - TTCPServer& TCPServer() { return mTCPServer->get(); } - + TNetwork& Network() { return mNetwork->get(); } + TServer& mServer; - std::optional> mTCPServer { std::nullopt }; + std::optional> mNetwork { std::nullopt }; bool mShutdown { false }; int mInternalPPS { 0 }; }; \ No newline at end of file diff --git a/include/TServer.h b/include/TServer.h index 38eef9a..19249a8 100644 --- a/include/TServer.h +++ b/include/TServer.h @@ -8,8 +8,7 @@ #include class TClient; -class TUDPServer; -class TTCPServer; +class TNetwork; class TPPSMonitor; class TServer final { @@ -25,12 +24,12 @@ public: void ForEachClient(const std::function)>& Fn); size_t ClientCount() const; - static void GlobalParser(const std::weak_ptr& Client, std::string Packet, TPPSMonitor& PPSMonitor, TUDPServer& UDPServer, TTCPServer& TCPServer); + static void GlobalParser(const std::weak_ptr& Client, std::string Packet, TPPSMonitor& PPSMonitor, TNetwork& Network); static void HandleEvent(TClient& c, const std::string& Data); private: TClientSet mClients; mutable RWMutex mClientsMutex; - static void ParseVehicle(TClient& c, const std::string& Pckt, TTCPServer& TCPServer, TUDPServer& UDPServer); + static void ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Network); static void Apply(TClient& c, int VID, const std::string& pckt); }; diff --git a/include/TUDPServer.h b/include/TUDPServer.h deleted file mode 100644 index abe75b0..0000000 --- a/include/TUDPServer.h +++ /dev/null @@ -1,28 +0,0 @@ -#pragma once - -#include "Client.h" -#include "Common.h" -#include "Compat.h" -#include "IThreaded.h" -#include "TPPSMonitor.h" -#include "TServer.h" - -class TUDPServer : public IThreaded { -public: - explicit TUDPServer(TServer& Server, TPPSMonitor& PPSMonitor, TTCPServer& TCPServer); - //~TUDPServer(); - - void operator()() override; - - void UDPSend(TClient& Client, std::string Data) const; - void SendToAll(TClient* c, const std::string& Data, bool Self, bool Rel); - -private: - TServer& mServer; - TPPSMonitor& mPPSMonitor; - TTCPServer& mTCPServer; - SOCKET mUDPSock {}; - bool mShutdown { false }; - - std::string UDPRcvFromClient(sockaddr_in& client) const; -}; \ No newline at end of file diff --git a/src/Common.cpp b/src/Common.cpp index da1e0f6..0fdba3b 100644 --- a/src/Common.cpp +++ b/src/Common.cpp @@ -21,6 +21,7 @@ void Application::GracefullyShutdown() { Handler(); } } + std::string Comp(std::string Data) { std::array C {}; // obsolete diff --git a/src/TLuaEngine.cpp b/src/TLuaEngine.cpp index 0c3fda1..94fd2d5 100644 --- a/src/TLuaEngine.cpp +++ b/src/TLuaEngine.cpp @@ -9,9 +9,8 @@ namespace fs = std::filesystem; // necessary as lua relies on global state TLuaEngine* TheEngine; -TLuaEngine::TLuaEngine(TServer& Server, TTCPServer& TCPServer, TUDPServer& UDPServer) - : mTCPServer(TCPServer) - , mUDPServer(UDPServer) +TLuaEngine::TLuaEngine(TServer& Server, TNetwork& Network) + : mNetwork(Network) , mServer(Server) { TheEngine = this; if (!fs::exists(Application::Settings.Resource)) { @@ -101,6 +100,3 @@ bool TLuaEngine::NewFile(const std::string& Path) { } return true; } - -/*TLuaEngine::~TLuaEngine() { -}*/ diff --git a/src/TLuaFile.cpp b/src/TLuaFile.cpp index 21d8c37..8a6ccf6 100644 --- a/src/TLuaFile.cpp +++ b/src/TLuaFile.cpp @@ -3,9 +3,8 @@ #include "Common.h" #include "CustomAssert.h" #include "TLuaEngine.h" +#include "TNetwork.h" #include "TServer.h" -#include "TTCPServer.h" -#include "TUDPServer.h" #include #include @@ -172,7 +171,7 @@ char* ThreadOrigin(TLuaFile* lua) { memcpy(Data, T.c_str(), T.size()); return Data; } -void SafeExecution(TLuaEngine& Engine, TLuaFile* lua, const std::string& FuncName) { +void SafeExecution(TLuaFile* lua, const std::string& FuncName) { lua_State* luaState = lua->GetState(); lua_getglobal(luaState, FuncName.c_str()); if (lua_isfunction(luaState, -1)) { @@ -192,19 +191,21 @@ void SafeExecution(TLuaEngine& Engine, TLuaFile* lua, const std::string& FuncNam ClearStack(luaState); } -void ExecuteAsync(TLuaEngine& Engine, TLuaFile* lua, const std::string& FuncName) { +void ExecuteAsync(TLuaFile* lua, const std::string& FuncName) { std::lock_guard lockGuard(lua->Lock); - SafeExecution(Engine, lua, FuncName); + SafeExecution(lua, FuncName); } + void CallAsync(TLuaFile* lua, const std::string& Func, int U) { //DebugPrintTID(); lua->SetStopThread(false); int D = 1000 / U; while (!lua->GetStopThread()) { - ExecuteAsync(Engine(), lua, Func); + ExecuteAsync(lua, Func); std::this_thread::sleep_for(std::chrono::milliseconds(D)); } } + int lua_StopThread(lua_State* L) { auto MaybeScript = Engine().GetScript(L); Assert(MaybeScript.has_value()); @@ -321,22 +322,22 @@ int lua_GetAllPlayers(lua_State* L) { return 0; return 1; } -int lua_GetIdentifiers(lua_State* L){ - if(lua_isnumber(L,1)){ +int lua_GetIdentifiers(lua_State* L) { + if (lua_isnumber(L, 1)) { auto MaybeClient = GetClient(Engine().Server(), int(lua_tonumber(L, 1))); if (MaybeClient && !MaybeClient.value().expired()) { auto IDs = MaybeClient.value().lock()->GetIdentifiers(); - if(IDs.empty()) + if (IDs.empty()) return 0; lua_newtable(L); - for(const std::string& ID : IDs){ - lua_pushstring(L, ID.substr(0,ID.find(':')).c_str()); + for (const std::string& ID : IDs) { + lua_pushstring(L, ID.substr(0, ID.find(':')).c_str()); lua_pushstring(L, ID.c_str()); lua_settable(L, -3); } - }else + } else return 0; - }else{ + } else { SendError(Engine(), L, "lua_GetIdentifiers wrong arguments"); return 0; } @@ -382,7 +383,7 @@ int lua_dropPlayer(lua_State* L) { Reason = std::string((" Reason : ")) + lua_tostring(L, 2); } auto c = MaybeClient.value().lock(); - Engine().TCPServer().Respond(*c, "C:Server:You have been Kicked from the server! " + Reason, true); + Engine().Network().Respond(*c, "C:Server:You have been Kicked from the server! " + Reason, true); c->SetStatus(-2); info(("Closing socket due to kick")); CloseSocketProper(c->GetTCPSock()); @@ -396,7 +397,7 @@ int lua_sendChat(lua_State* L) { int ID = int(lua_tointeger(L, 1)); if (ID == -1) { std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2)); - Engine().UDPServer().SendToAll(nullptr, Packet, true, true); + Engine().Network().SendToAll(nullptr, Packet, true, true); } else { auto MaybeClient = GetClient(Engine().Server(), ID); if (MaybeClient && !MaybeClient.value().expired()) { @@ -404,7 +405,7 @@ int lua_sendChat(lua_State* L) { if (!c->IsSynced()) return 0; std::string Packet = "C:Server: " + std::string(lua_tostring(L, 2)); - Engine().TCPServer().Respond(*c, Packet, true); + Engine().Network().Respond(*c, Packet, true); } else SendError(Engine(), L, ("SendChatMessage invalid argument [1] invalid ID")); } @@ -431,7 +432,7 @@ int lua_RemoveVehicle(lua_State* L) { auto c = MaybeClient.value().lock(); if (!c->GetCarData(VID).empty()) { std::string Destroy = "Od:" + std::to_string(PID) + "-" + std::to_string(VID); - Engine().UDPServer().SendToAll(nullptr, Destroy, true, true); + Engine().Network().SendToAll(nullptr, Destroy, true, true); c->DeleteCar(VID); } } else @@ -463,7 +464,7 @@ int lua_RemoteEvent(lua_State* L) { int ID = int(lua_tointeger(L, 1)); std::string Packet = "E:" + std::string(lua_tostring(L, 2)) + ":" + std::string(lua_tostring(L, 3)); if (ID == -1) - Engine().UDPServer().SendToAll(nullptr, Packet, true, true); + Engine().Network().SendToAll(nullptr, Packet, true, true); else { auto MaybeClient = GetClient(Engine().Server(), ID); if (!MaybeClient || MaybeClient.value().expired()) { @@ -471,7 +472,7 @@ int lua_RemoteEvent(lua_State* L) { return 0; } auto c = MaybeClient.value().lock(); - Engine().TCPServer().Respond(*c, Packet, true); + Engine().Network().Respond(*c, Packet, true); } return 0; } diff --git a/src/TTCPServer.cpp b/src/TNetwork.cpp similarity index 70% rename from src/TTCPServer.cpp rename to src/TNetwork.cpp index e4b9a20..81619a0 100644 --- a/src/TTCPServer.cpp +++ b/src/TNetwork.cpp @@ -1,12 +1,195 @@ -#include "TTCPServer.h" -#include "TLuaEngine.h" -#include "TLuaFile.h" -#include "TResourceManager.h" -#include "TUDPServer.h" +#include "TNetwork.h" + +#include "Client.h" #include #include #include +TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager) + : mServer(Server) + , mPPSMonitor(PPSMonitor) + , mResourceManager(ResourceManager) { + Application::RegisterShutdownHandler([&] { + if (mUDPThread.joinable()) { + debug("shutting down TCPServer"); + mShutdown = true; + mUDPThread.detach(); + debug("shut down TCPServer"); + } + }); + Application::RegisterShutdownHandler([&] { + if (mUDPThread.joinable()) { + debug("shutting down TCPServer"); + mShutdown = true; + mTCPThread.detach(); + debug("shut down TCPServer"); + } + }); + mTCPThread = std::thread(&TNetwork::TCPServerMain, this); + mUDPThread = std::thread(&TNetwork::UDPServerMain, this); +} + +void TNetwork::UDPServerMain() { +#ifdef WIN32 + WSADATA data; + if (WSAStartup(514, &data)) { + error(("Can't start Winsock!")); + //return; + } + + mUDPSock = 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(Application::Settings.Port); // Convert from little to big endian + + // Try and bind the socket to the IP and port + if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { + error(("Can't bind socket!") + std::to_string(WSAGetLastError())); + std::this_thread::sleep_for(std::chrono::seconds(5)); + exit(-1); + //return; + } +#else // unix + mUDPSock = socket(AF_INET, SOCK_DGRAM, 0); + // Create a server hint structure for the server + sockaddr_in serverAddr {}; + serverAddr.sin_addr.s_addr = INADDR_ANY; //Any Local + serverAddr.sin_family = AF_INET; // Address format is IPv4 + serverAddr.sin_port = htons(uint16_t(Application::Settings.Port)); // Convert from little to big endian + + // Try and bind the socket to the IP and port + if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) != 0) { + error(("Can't bind socket!") + std::string(strerror(errno))); + std::this_thread::sleep_for(std::chrono::seconds(5)); + exit(-1); + //return; + } +#endif + + info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") + + std::to_string(Application::Settings.MaxPlayers) + (" Clients")); + while (!mShutdown) { + try { + sockaddr_in client {}; + std::string Data = UDPRcvFromClient(client); //Receives any data from Socket + size_t Pos = Data.find(':'); + if (Data.empty() || 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 = uint8_t(Data.at(0)) - 1; + mServer.ForEachClient([&](std::weak_ptr ClientPtr) -> bool { + if (!ClientPtr.expired()) { + auto Client = ClientPtr.lock(); + if (Client->GetID() == ID) { + Client->SetUDPAddr(client); + Client->SetIsConnected(true); + TServer::GlobalParser(ClientPtr, Data.substr(2), mPPSMonitor, *this); + } + } + return true; + }); + } catch (const std::exception& e) { + error(("fatal: ") + std::string(e.what())); + } + } +} + +void TNetwork::TCPServerMain() { +#ifdef WIN32 + WSADATA wsaData; + if (WSAStartup(514, &wsaData)) { + error("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(Application::Settings.Port); + if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { + error("Can't bind socket! " + std::to_string(WSAGetLastError())); + std::this_thread::sleep_for(std::chrono::seconds(5)); + exit(-1); + } + if (Listener == -1) { + error("Invalid listening socket"); + return; + } + if (listen(Listener, SOMAXCONN)) { + error("listener failed " + std::to_string(GetLastError())); + return; + } + info("Vehicle event network online"); + do { + try { + client = accept(Listener, nullptr, nullptr); + if (client == -1) { + warn("Got an invalid client socket on connect! Skipping..."); + continue; + } + std::thread ID(&TTCPServer::Identify, this, client); + ID.detach(); + } catch (const std::exception& e) { + error("fatal: " + std::string(e.what())); + } + } while (client); + + CloseSocketProper(client); + WSACleanup(); +#else // unix + // wondering why we need slightly different implementations of this? + // ask ms. + SOCKET client = -1; + SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + int optval = 1; + setsockopt(Listener, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); + // TODO: check optval or return value idk + sockaddr_in addr {}; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_family = AF_INET; + addr.sin_port = htons(uint16_t(Application::Settings.Port)); + if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) { + error(("Can't bind socket! ") + std::string(strerror(errno))); + std::this_thread::sleep_for(std::chrono::seconds(5)); + exit(-1); + } + if (Listener == -1) { + error(("Invalid listening socket")); + return; + } + if (listen(Listener, SOMAXCONN)) { + error(("listener failed ") + std::string(strerror(errno))); + return; + } + info(("Vehicle event network online")); + do { + try { + if (mShutdown) { + debug("shutdown during TCP wait for accept loop"); + break; + } + client = accept(Listener, nullptr, nullptr); + if (client == -1) { + warn(("Got an invalid client socket on connect! Skipping...")); + continue; + } + std::thread ID(&TNetwork::Identify, this, client); + ID.detach(); // TODO: Add to a queue and attempt to join periodically + } catch (const std::exception& e) { + error(("fatal: ") + std::string(e.what())); + } + } while (client); + + debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__)); + + CloseSocketProper(client); +#endif +} + #undef GetObject //Fixes Windows #include "rapidjson/document.h" @@ -14,24 +197,7 @@ #include "rapidjson/writer.h" namespace json = rapidjson; -bool TCPSend(std::weak_ptr c, const std::string& Data); -bool TCPSend(TClient& c, const std::string& Data); - -TTCPServer::TTCPServer(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager) - : mServer(Server) - , mPPSMonitor(PPSMonitor) - , mResourceManager(ResourceManager) { - Application::RegisterShutdownHandler([&] {if (mThread.joinable()) { - debug("shutting down TCPServer"); - mShutdown = true; - // FIXME: Join once TCPServer can timeout on a read, accept, etc. - mThread.detach(); - debug("shut down TCPServer"); - } }); - Start(); -} - -void TTCPServer::Identify(SOCKET TCPSock) { +void TNetwork::Identify(SOCKET TCPSock) { char Code; if (recv(TCPSock, &Code, 1, 0) != 1) { CloseSocketProper(TCPSock); @@ -46,7 +212,7 @@ void TTCPServer::Identify(SOCKET TCPSock) { } } -void TTCPServer::HandleDownload(SOCKET TCPSock) { +void TNetwork::HandleDownload(SOCKET TCPSock) { char D; if (recv(TCPSock, &D, 1, 0) != 1) { CloseSocketProper(TCPSock); @@ -64,7 +230,7 @@ void TTCPServer::HandleDownload(SOCKET TCPSock) { }); } -void TTCPServer::Authentication(SOCKET TCPSock) { +void TNetwork::Authentication(SOCKET TCPSock) { auto Client = CreateClient(TCPSock); std::string Rc; @@ -160,13 +326,13 @@ void TTCPServer::Authentication(SOCKET TCPSock) { ClientKick(*Client, "Server full!"); } -std::shared_ptr TTCPServer::CreateClient(SOCKET TCPSock) { +std::shared_ptr TNetwork::CreateClient(SOCKET TCPSock) { auto c = std::make_shared(mServer); c->SetTCPSock(TCPSock); return c; } -bool TTCPServer::TCPSend(TClient& c, const std::string& Data, bool IsSync) { +bool TNetwork::TCPSend(TClient& c, const std::string& Data, bool IsSync) { if (!IsSync) { if (c.IsSyncing()) { c.EnqueueMissedPacketDuringSyncing(Data); @@ -204,7 +370,7 @@ bool TTCPServer::TCPSend(TClient& c, const std::string& Data, bool IsSync) { return true; } -bool TTCPServer::CheckBytes(TClient& c, int32_t BytesRcv) { +bool TNetwork::CheckBytes(TClient& c, int32_t BytesRcv) { if (BytesRcv == 0) { debug("(TCP) Connection closing..."); if (c.GetStatus() > -1) @@ -225,7 +391,7 @@ bool TTCPServer::CheckBytes(TClient& c, int32_t BytesRcv) { return true; } -std::string TTCPServer::TCPRcv(TClient& c) { +std::string TNetwork::TCPRcv(TClient& c) { int32_t Header, BytesRcv = 0, Temp; if (c.GetStatus() < 0) return ""; @@ -289,14 +455,14 @@ std::string TTCPServer::TCPRcv(TClient& c) { return Ret; } -void TTCPServer::ClientKick(TClient& c, const std::string& R) { +void TNetwork::ClientKick(TClient& c, const std::string& R) { info("Client kicked: " + R); TCPSend(c, "E" + R); c.SetStatus(-2); CloseSocketProper(c.GetTCPSock()); } -void TTCPServer::TCPClient(const std::weak_ptr& c) { +void TNetwork::TCPClient(const std::weak_ptr& c) { // TODO: the c.expired() might cause issues here, remove if you end up here with your debugger if (c.expired() || c.lock()->GetTCPSock() == -1) { mServer.RemoveClient(c); @@ -310,7 +476,7 @@ void TTCPServer::TCPClient(const std::weak_ptr& c) { if (Client->GetStatus() <= -1) { break; } - TServer::GlobalParser(c, TCPRcv(*Client), mPPSMonitor, UDPServer(), *this); + TServer::GlobalParser(c, TCPRcv(*Client), mPPSMonitor, *this); } if (!c.expired()) { auto Client = c.lock(); @@ -320,7 +486,7 @@ void TTCPServer::TCPClient(const std::weak_ptr& c) { } } -void TTCPServer::UpdatePlayer(TClient& Client) { +void TNetwork::UpdatePlayer(TClient& Client) { std::string Packet = ("Ss") + std::to_string(mServer.ClientCount()) + "/" + std::to_string(Application::Settings.MaxPlayers) + ":"; mServer.ForEachClient([&](const std::weak_ptr& ClientPtr) -> bool { if (!ClientPtr.expired()) { @@ -333,7 +499,7 @@ void TTCPServer::UpdatePlayer(TClient& Client) { Respond(Client, Packet, true); } -void TTCPServer::OnDisconnect(const std::weak_ptr& ClientPtr, bool kicked) { +void TNetwork::OnDisconnect(const std::weak_ptr& ClientPtr, bool kicked) { Assert(!ClientPtr.expired()); auto LockedClientPtr = ClientPtr.lock(); TClient& c = *LockedClientPtr; @@ -346,13 +512,13 @@ void TTCPServer::OnDisconnect(const std::weak_ptr& ClientPtr, bool kick } // End Vehicle Data Lock Scope for (auto& v : VehicleData) { Packet = "Od:" + std::to_string(c.GetID()) + "-" + std::to_string(v.ID()); - UDPServer().SendToAll(&c, Packet, false, true); + SendToAll(&c, Packet, false, true); } if (kicked) Packet = ("L") + c.GetName() + (" was kicked!"); else Packet = ("L") + c.GetName() + (" left the server!"); - UDPServer().SendToAll(&c, Packet, false, true); + SendToAll(&c, Packet, false, true); Packet.clear(); TriggerLuaEvent(("onPlayerDisconnect"), false, nullptr, std::make_unique(TLuaArg { { c.GetID() } }), false); if (c.GetTCPSock()) @@ -362,7 +528,7 @@ void TTCPServer::OnDisconnect(const std::weak_ptr& ClientPtr, bool kick mServer.RemoveClient(ClientPtr); } -int TTCPServer::OpenID() { +int TNetwork::OpenID() { int ID = 0; bool found; do { @@ -381,7 +547,7 @@ int TTCPServer::OpenID() { return ID; } -void TTCPServer::OnConnect(const std::weak_ptr& c) { +void TNetwork::OnConnect(const std::weak_ptr& c) { Assert(!c.expired()); info("Client connected"); auto LockedClient = c.lock(); @@ -396,7 +562,7 @@ void TTCPServer::OnConnect(const std::weak_ptr& c) { TriggerLuaEvent("onPlayerJoining", false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID() } }), false); } -void TTCPServer::SyncResources(TClient& c) { +void TNetwork::SyncResources(TClient& c) { #ifndef DEBUG try { #endif @@ -416,7 +582,7 @@ void TTCPServer::SyncResources(TClient& c) { #endif } -void TTCPServer::Parse(TClient& c, const std::string& Packet) { +void TNetwork::Parse(TClient& c, const std::string& Packet) { if (Packet.empty()) return; char Code = Packet.at(0), SubCode = 0; @@ -440,7 +606,7 @@ void TTCPServer::Parse(TClient& c, const std::string& Packet) { } } -void TTCPServer::SendFile(TClient& c, const std::string& Name) { +void TNetwork::SendFile(TClient& c, const std::string& Name) { info(c.GetName() + " requesting : " + Name.substr(Name.find_last_of('/'))); if (!std::filesystem::exists(Name)) { @@ -482,7 +648,7 @@ void TTCPServer::SendFile(TClient& c, const std::string& Name) { } } -void TTCPServer::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std::string& Name) { +void TNetwork::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const std::string& Name) { std::ifstream f(Name.c_str(), std::ios::binary); uint32_t Split = 0x7735940; //125MB char* Data; @@ -522,7 +688,7 @@ void TTCPServer::SplitLoad(TClient& c, size_t Sent, size_t Size, bool D, const s f.close(); } -bool TTCPServer::TCPSendRaw(SOCKET C, char* Data, int32_t Size) { +bool TNetwork::TCPSendRaw(SOCKET C, char* Data, int32_t Size) { intmax_t Sent = 0; do { intmax_t Temp = send(C, &Data[Sent], int(Size - Sent), 0); @@ -536,7 +702,7 @@ bool TTCPServer::TCPSendRaw(SOCKET C, char* Data, int32_t Size) { return true; } -void TTCPServer::SendLarge(TClient& c, std::string Data, bool isSync) { +void TNetwork::SendLarge(TClient& c, std::string Data, bool isSync) { if (Data.length() > 400) { std::string CMP(Comp(Data)); Data = "ABG:" + CMP; @@ -544,7 +710,7 @@ void TTCPServer::SendLarge(TClient& c, std::string Data, bool isSync) { TCPSend(c, Data, isSync); } -void TTCPServer::Respond(TClient& c, const std::string& MSG, bool Rel, bool isSync) { +void TNetwork::Respond(TClient& c, const std::string& MSG, bool Rel, bool isSync) { char C = MSG.at(0); if (Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E') { if (C == 'O' || C == 'T' || MSG.length() > 1000) { @@ -553,11 +719,11 @@ void TTCPServer::Respond(TClient& c, const std::string& MSG, bool Rel, bool isSy TCPSend(c, MSG, isSync); } } else { - UDPServer().UDPSend(c, MSG); + UDPSend(c, MSG); } } -void TTCPServer::SyncClient(const std::weak_ptr& c) { +void TNetwork::SyncClient(const std::weak_ptr& c) { if (c.expired()) { return; } @@ -567,7 +733,7 @@ void TTCPServer::SyncClient(const std::weak_ptr& c) { // Syncing, later set isSynced // after syncing is done, we apply all packets they missed Respond(*LockedClient, ("Sn") + LockedClient->GetName(), true); - UDPServer().SendToAll(LockedClient.get(), ("JWelcome ") + LockedClient->GetName() + "!", false, true); + SendToAll(LockedClient.get(), ("JWelcome ") + LockedClient->GetName() + "!", false, true); TriggerLuaEvent(("onPlayerJoin"), false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID() } }), false); LockedClient->SetIsSyncing(true); bool Return = false; @@ -600,104 +766,91 @@ void TTCPServer::SyncClient(const std::weak_ptr& c) { info(LockedClient->GetName() + (" is now synced!")); } -void TTCPServer::SetUDPServer(TUDPServer& UDPServer) { - mUDPServer = std::ref(UDPServer); +void TNetwork::SendToAll(TClient* c, const std::string& Data, bool Self, bool Rel) { + if (!Self) + Assert(c); + char C = Data.at(0); + mServer.ForEachClient([&](std::weak_ptr ClientPtr) -> bool { + if (!ClientPtr.expired()) { + auto Client = ClientPtr.lock(); + if (Self || Client.get() != c) { + if (Client->IsSynced() || Client->IsSyncing()) { + 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); + } + } + } + return true; + }); } -void TTCPServer::operator()() { - while (!mUDPServer.has_value()) { - // hard spin - std::this_thread::sleep_for(std::chrono::milliseconds(1)); +void TNetwork::UDPSend(TClient& Client, std::string Data) const { + if (!Client.IsConnected() || Client.GetStatus() < 0) { + // this can happen if we try to send a packet to a client that is either + // 1. not yet fully connected, or + // 2. disconnected and not yet fully removed + // this is fine can can be ignored :^) + return; + } + sockaddr_in Addr = Client.GetUDPAddr(); + auto AddrSize = sizeof(Client.GetUDPAddr()); + if (Data.length() > 400) { + std::string CMP(Comp(Data)); + Data = "ABG:" + CMP; } #ifdef WIN32 - WSADATA wsaData; - if (WSAStartup(514, &wsaData)) { - error("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(Application::Settings.Port); - if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) { - error("Can't bind socket! " + std::to_string(WSAGetLastError())); - std::this_thread::sleep_for(std::chrono::seconds(5)); - exit(-1); - } - if (Listener == -1) { - error("Invalid listening socket"); - return; - } - if (listen(Listener, SOMAXCONN)) { - error("listener failed " + std::to_string(GetLastError())); - return; - } - info("Vehicle event network online"); - do { - try { - client = accept(Listener, nullptr, nullptr); - if (client == -1) { - warn("Got an invalid client socket on connect! Skipping..."); - continue; - } - std::thread ID(&TTCPServer::Identify, this, client); - ID.detach(); - } catch (const std::exception& e) { - error("fatal: " + std::string(e.what())); - } - } while (client); + int sendOk; + int len = static_cast(Data.size()); +#else + int64_t sendOk; + size_t len = Data.size(); +#endif // WIN32 - CloseSocketProper(client); - WSACleanup(); + sendOk = sendto(mUDPSock, Data.c_str(), len, 0, (sockaddr*)&Addr, int(AddrSize)); +#ifdef WIN32 + if (sendOk == -1) { + debug(("(UDP) Send Failed Code : ") + std::to_string(WSAGetLastError())); + if (Client.GetStatus() > -1) + Client.SetStatus(-1); + } else if (sendOk == 0) { + debug(("(UDP) sendto returned 0")); + if (Client.GetStatus() > -1) + Client.SetStatus(-1); + } #else // unix - // wondering why we need slightly different implementations of this? - // ask ms. - SOCKET client = -1; - SOCKET Listener = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - int optval = 1; - setsockopt(Listener, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); - // TODO: check optval or return value idk - sockaddr_in addr {}; - addr.sin_addr.s_addr = INADDR_ANY; - addr.sin_family = AF_INET; - addr.sin_port = htons(uint16_t(Application::Settings.Port)); - if (bind(Listener, (sockaddr*)&addr, sizeof(addr)) != 0) { - error(("Can't bind socket! ") + std::string(strerror(errno))); - std::this_thread::sleep_for(std::chrono::seconds(5)); - exit(-1); + if (sendOk == -1) { + debug(("(UDP) Send Failed Code : ") + std::string(strerror(errno))); + if (Client.GetStatus() > -1) + Client.SetStatus(-1); + } else if (sendOk == 0) { + debug(("(UDP) sendto returned 0")); + if (Client.GetStatus() > -1) + Client.SetStatus(-1); } - if (Listener == -1) { - error(("Invalid listening socket")); - return; - } - if (listen(Listener, SOMAXCONN)) { - error(("listener failed ") + std::string(strerror(errno))); - return; - } - info(("Vehicle event network online")); - do { - try { - if (mShutdown) { - debug("shutdown during TCP wait for accept loop"); - break; - } - client = accept(Listener, nullptr, nullptr); - if (client == -1) { - warn(("Got an invalid client socket on connect! Skipping...")); - continue; - } - std::thread ID(&TTCPServer::Identify, this, client); - ID.detach(); // TODO: Add to a queue and attempt to join periodically - } catch (const std::exception& e) { - error(("fatal: ") + std::string(e.what())); - } - } while (client); - - debug("all ok, arrived at " + std::string(__func__) + ":" + std::to_string(__LINE__)); - - CloseSocketProper(client); -#endif +#endif // WIN32 +} + +std::string TNetwork::UDPRcvFromClient(sockaddr_in& client) const { + size_t clientLength = sizeof(client); + std::array Ret {}; +#ifdef WIN32 + auto Rcv = recvfrom(mUDPSock, Ret.data(), int(Ret.size()), 0, (sockaddr*)&client, (int*)&clientLength); +#else // unix + int64_t Rcv = recvfrom(mUDPSock, Ret.data(), Ret.size(), 0, (sockaddr*)&client, (socklen_t*)&clientLength); +#endif // WIN32 + + if (Rcv == -1) { +#ifdef WIN32 + error(("(UDP) Error receiving from Client! Code : ") + std::to_string(WSAGetLastError())); +#else // unix + error(("(UDP) Error receiving from Client! Code : ") + std::string(strerror(errno))); +#endif // WIN32 + return ""; + } + return std::string(Ret.begin(), Ret.begin() + Rcv); } -/*TTCPServer::~TTCPServer() { -}*/ diff --git a/src/TPPSMonitor.cpp b/src/TPPSMonitor.cpp index 02e8b09..9564ee9 100644 --- a/src/TPPSMonitor.cpp +++ b/src/TPPSMonitor.cpp @@ -1,6 +1,6 @@ #include "TPPSMonitor.h" #include "Client.h" -#include "TTCPServer.h" +#include "TNetwork.h" TPPSMonitor::TPPSMonitor(TServer& Server) : mServer(Server) { @@ -16,7 +16,7 @@ TPPSMonitor::TPPSMonitor(TServer& Server) Start(); } void TPPSMonitor::operator()() { - while (!mTCPServer) { + while (!mNetwork) { // hard spi std::this_thread::sleep_for(std::chrono::milliseconds(1)); } @@ -46,7 +46,7 @@ void TPPSMonitor::operator()() { return true; }); for (auto& ClientToKick : TimedOutClients) { - TCPServer().ClientKick(*ClientToKick, "Timeout (no ping for >10 seconds)"); + Network().ClientKick(*ClientToKick, "Timeout (no ping for >10 seconds)"); } TimedOutClients.clear(); if (C == 0 || mInternalPPS == 0) { diff --git a/src/TServer.cpp b/src/TServer.cpp index b91b7cd..fb61e90 100644 --- a/src/TServer.cpp +++ b/src/TServer.cpp @@ -2,8 +2,7 @@ #include "Client.h" #include "Common.h" #include "TPPSMonitor.h" -#include "TTCPServer.h" -#include "TUDPServer.h" +#include "TNetwork.h" #include #include #include @@ -14,8 +13,6 @@ #include "rapidjson/stringbuffer.h" #include "rapidjson/writer.h" - - namespace json = rapidjson; TServer::TServer(int argc, char** argv) { @@ -64,7 +61,7 @@ size_t TServer::ClientCount() const { return mClients.size(); } -void TServer::GlobalParser(const std::weak_ptr& Client, std::string Packet, TPPSMonitor& PPSMonitor, TUDPServer& UDPServer, TTCPServer& TCPServer) { +void TServer::GlobalParser(const std::weak_ptr& Client, std::string Packet, TPPSMonitor& PPSMonitor, TNetwork& Network) { if (Packet.find("Zp") != std::string::npos && Packet.size() > 500) { abort(); } @@ -86,7 +83,7 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac //V to Z if (Code <= 90 && Code >= 86) { PPSMonitor.IncrementInternalPPS(); - UDPServer.SendToAll(LockedClient.get(), Packet, false, false); + Network.SendToAll(LockedClient.get(), Packet, false, false); return; } switch (Code) { @@ -94,24 +91,24 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac #ifdef DEBUG debug(std::string("got 'H' packet: '") + Packet + "' (" + std::to_string(Packet.size()) + ")"); #endif - TCPServer.SyncClient(Client); + Network.SyncClient(Client); return; case 'p': - TCPServer.Respond(*LockedClient, ("p"), false); - TCPServer.UpdatePlayer(*LockedClient); + Network.Respond(*LockedClient, ("p"), false); + Network.UpdatePlayer(*LockedClient); LockedClient->UpdatePingTime(); return; case 'O': if (Packet.length() > 1000) { debug(("Received data from: ") + LockedClient->GetName() + (" Size: ") + std::to_string(Packet.length())); } - ParseVehicle(*LockedClient, Packet, TCPServer, UDPServer); + ParseVehicle(*LockedClient, Packet, Network); return; case 'J': #ifdef DEBUG debug(std::string(("got 'J' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); #endif - UDPServer.SendToAll(LockedClient.get(), Packet, false, true); + Network.SendToAll(LockedClient.get(), Packet, false, true); return; case 'C': #ifdef DEBUG @@ -122,7 +119,7 @@ void TServer::GlobalParser(const std::weak_ptr& Client, std::string Pac Res = TriggerLuaEvent("onChatMessage", false, nullptr, std::make_unique(TLuaArg { { LockedClient->GetID(), LockedClient->GetName(), Packet.substr(Packet.find(':', 3) + 1) } }), true); if (std::any_cast(Res)) break; - UDPServer.SendToAll(nullptr, Packet, true, true); + Network.SendToAll(nullptr, Packet, true, true); return; case 'E': #ifdef DEBUG @@ -156,13 +153,13 @@ void TServer::HandleEvent(TClient& c, const std::string& Data) { } } -void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TTCPServer& TCPServer, TUDPServer& UDPServer) { +void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TNetwork& Network) { if (Pckt.length() < 4) return; std::string Packet = Pckt; char Code = Packet.at(1); int PID = -1; - int VID = -1,Pos; + int VID = -1, Pos; std::string Data = Packet.substr(3), pid, vid; switch (Code) { //Spawned Destroyed Switched/Moved NotFound Reset case 's': @@ -175,13 +172,13 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TTCPServer& TCPS Packet = "Os:" + c.GetRoles() + ":" + c.GetName() + ":" + std::to_string(c.GetID()) + "-" + std::to_string(CarID) + Packet.substr(4); auto Res = TriggerLuaEvent(("onVehicleSpawn"), false, nullptr, std::make_unique(TLuaArg { { c.GetID(), CarID, Packet.substr(3) } }), true); if (c.GetCarCount() >= Application::Settings.MaxCars || std::any_cast(Res)) { - TCPServer.Respond(c, Packet, true); + Network.Respond(c, Packet, true); std::string Destroy = "Od:" + std::to_string(c.GetID()) + "-" + std::to_string(CarID); - TCPServer.Respond(c, Destroy, true); + Network.Respond(c, Destroy, true); debug(c.GetName() + (" (force : car limit/lua) removed ID ") + std::to_string(CarID)); } else { c.AddNewCar(CarID, Packet); - UDPServer.SendToAll(nullptr, Packet, true, true); + Network.SendToAll(nullptr, Packet, true, true); } } return; @@ -200,11 +197,11 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TTCPServer& TCPS std::make_unique(TLuaArg { { c.GetID(), VID, Packet.substr(3) } }), true); if (!std::any_cast(Res)) { - UDPServer.SendToAll(&c, Packet, false, true); + Network.SendToAll(&c, Packet, false, true); Apply(c, VID, Packet); } else { std::string Destroy = "Od:" + std::to_string(c.GetID()) + "-" + std::to_string(VID); - TCPServer.Respond(c, Destroy, true); + Network.Respond(c, Destroy, true); c.DeleteCar(VID); } } @@ -220,7 +217,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TTCPServer& TCPS VID = stoi(vid); } if (PID != -1 && VID != -1 && PID == c.GetID()) { - UDPServer.SendToAll(nullptr, Packet, true, true); + Network.SendToAll(nullptr, Packet, true, true); TriggerLuaEvent(("onVehicleDeleted"), false, nullptr, std::make_unique(TLuaArg { { c.GetID(), VID } }), false); c.DeleteCar(VID); @@ -233,7 +230,7 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TTCPServer& TCPS #endif Pos = int(Data.find('-')); pid = Data.substr(0, Pos++); - vid = Data.substr(Pos,Data.find(':') - Pos); + vid = Data.substr(Pos, Data.find(':') - Pos); if (pid.find_first_not_of("0123456789") == std::string::npos && vid.find_first_not_of("0123456789") == std::string::npos) { PID = stoi(pid); @@ -243,16 +240,16 @@ void TServer::ParseVehicle(TClient& c, const std::string& Pckt, TTCPServer& TCPS if (PID != -1 && VID != -1 && PID == c.GetID()) { Data = Data.substr(Data.find('{')); TriggerLuaEvent("onVehicleReset", false, nullptr, - std::make_unique(TLuaArg {{ c.GetID(), VID, Data}}), - false); - UDPServer.SendToAll(&c, Packet, false, true); + std::make_unique(TLuaArg { { c.GetID(), VID, Data } }), + false); + Network.SendToAll(&c, Packet, false, true); } return; case 't': #ifdef DEBUG debug(std::string(("got 'Ot' packet: '")) + Packet + ("' (") + std::to_string(Packet.size()) + (")")); #endif - UDPServer.SendToAll(&c, Packet, false, true); + Network.SendToAll(&c, Packet, false, true); return; default: #ifdef DEBUG diff --git a/src/TUDPServer.cpp b/src/TUDPServer.cpp deleted file mode 100644 index 1217062..0000000 --- a/src/TUDPServer.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include "TUDPServer.h" -#include "CustomAssert.h" -#include "TTCPServer.h" -#include -#include -#include -#include - -TUDPServer::TUDPServer(TServer& Server, TPPSMonitor& PPSMonitor, TTCPServer& TCPServer) - : mServer(Server) - , mPPSMonitor(PPSMonitor) - , mTCPServer(TCPServer) { - Application::RegisterShutdownHandler([&] {if (mThread.joinable()) { - debug("shutting down UDPServer"); - mShutdown = true; - // FIXME: Once we use boost for UDP, set up a timeout so this doesn't block - mThread.detach(); - debug("shut down UDPServer"); - } }); - Start(); -} - -void TUDPServer::operator()() { -#ifdef WIN32 - WSADATA data; - if (WSAStartup(514, &data)) { - error(("Can't start Winsock!")); - //return; - } - - mUDPSock = 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(Application::Settings.Port); // Convert from little to big endian - - // Try and bind the socket to the IP and port - if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) { - error(("Can't bind socket!") + std::to_string(WSAGetLastError())); - std::this_thread::sleep_for(std::chrono::seconds(5)); - exit(-1); - //return; - } -#else // unix - mUDPSock = socket(AF_INET, SOCK_DGRAM, 0); - // Create a server hint structure for the server - sockaddr_in serverAddr {}; - serverAddr.sin_addr.s_addr = INADDR_ANY; //Any Local - serverAddr.sin_family = AF_INET; // Address format is IPv4 - serverAddr.sin_port = htons(uint16_t(Application::Settings.Port)); // Convert from little to big endian - - // Try and bind the socket to the IP and port - if (bind(mUDPSock, (sockaddr*)&serverAddr, sizeof(serverAddr)) != 0) { - error(("Can't bind socket!") + std::string(strerror(errno))); - std::this_thread::sleep_for(std::chrono::seconds(5)); - exit(-1); - //return; - } -#endif - - info(("Vehicle data network online on port ") + std::to_string(Application::Settings.Port) + (" with a Max of ") - + std::to_string(Application::Settings.MaxPlayers) + (" Clients")); - while (!mShutdown) { - try { - sockaddr_in client {}; - std::string Data = UDPRcvFromClient(client); //Receives any data from Socket - size_t Pos = Data.find(':'); - if (Data.empty() || 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 = uint8_t(Data.at(0)) - 1; - mServer.ForEachClient([&](std::weak_ptr ClientPtr) -> bool { - if (!ClientPtr.expired()) { - auto Client = ClientPtr.lock(); - if (Client->GetID() == ID) { - Client->SetUDPAddr(client); - Client->SetIsConnected(true); - TServer::GlobalParser(ClientPtr, Data.substr(2), mPPSMonitor, *this, mTCPServer); - } - } - return true; - }); - } catch (const std::exception& e) { - error(("fatal: ") + std::string(e.what())); - } - } -} - -void TUDPServer::SendToAll(TClient* c, const std::string& Data, bool Self, bool Rel) { - if (!Self) - Assert(c); - char C = Data.at(0); - mServer.ForEachClient([&](std::weak_ptr ClientPtr) -> bool { - if (!ClientPtr.expired()) { - auto Client = ClientPtr.lock(); - if (Self || Client.get() != c) { - if (Client->IsSynced() || Client->IsSyncing()) { - if (Rel || C == 'W' || C == 'Y' || C == 'V' || C == 'E') { - if (C == 'O' || C == 'T' || Data.length() > 1000) - mTCPServer.SendLarge(*Client, Data); - else - mTCPServer.TCPSend(*Client, Data); - } else - UDPSend(*Client, Data); - } - } - } - return true; - }); -} - -void TUDPServer::UDPSend(TClient& Client, std::string Data) const { - if (!Client.IsConnected() || Client.GetStatus() < 0) { - // this can happen if we try to send a packet to a client that is either - // 1. not yet fully connected, or - // 2. disconnected and not yet fully removed - // this is fine can can be ignored :^) - return; - } - sockaddr_in Addr = Client.GetUDPAddr(); - auto AddrSize = sizeof(Client.GetUDPAddr()); - if (Data.length() > 400) { - std::string CMP(Comp(Data)); - Data = "ABG:" + CMP; - } -#ifdef WIN32 - int sendOk; - int len = static_cast(Data.size()); -#else - int64_t sendOk; - size_t len = Data.size(); -#endif // WIN32 - - sendOk = sendto(mUDPSock, Data.c_str(), len, 0, (sockaddr*)&Addr, int(AddrSize)); -#ifdef WIN32 - if (sendOk == -1) { - debug(("(UDP) Send Failed Code : ") + std::to_string(WSAGetLastError())); - if (Client.GetStatus() > -1) - Client.SetStatus(-1); - } else if (sendOk == 0) { - debug(("(UDP) sendto returned 0")); - if (Client.GetStatus() > -1) - Client.SetStatus(-1); - } -#else // unix - if (sendOk == -1) { - debug(("(UDP) Send Failed Code : ") + std::string(strerror(errno))); - if (Client.GetStatus() > -1) - Client.SetStatus(-1); - } else if (sendOk == 0) { - debug(("(UDP) sendto returned 0")); - if (Client.GetStatus() > -1) - Client.SetStatus(-1); - } -#endif // WIN32 -} - -std::string TUDPServer::UDPRcvFromClient(sockaddr_in& client) const { - size_t clientLength = sizeof(client); - std::array Ret {}; -#ifdef WIN32 - auto Rcv = recvfrom(mUDPSock, Ret.data(), int(Ret.size()), 0, (sockaddr*)&client, (int*)&clientLength); -#else // unix - int64_t Rcv = recvfrom(mUDPSock, Ret.data(), Ret.size(), 0, (sockaddr*)&client, (socklen_t*)&clientLength); -#endif // WIN32 - - if (Rcv == -1) { -#ifdef WIN32 - error(("(UDP) Error receiving from Client! Code : ") + std::to_string(WSAGetLastError())); -#else // unix - error(("(UDP) Error receiving from Client! Code : ") + std::string(strerror(errno))); -#endif // WIN32 - return ""; - } - return std::string(Ret.begin(), Ret.begin() + Rcv); -} - -/*TUDPServer::~TUDPServer() { -}*/ diff --git a/src/main.cpp b/src/main.cpp index 99d6cf9..0c8d49d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,11 +2,10 @@ #include "TConfig.h" #include "THeartbeatThread.h" #include "TLuaEngine.h" +#include "TNetwork.h" #include "TPPSMonitor.h" #include "TResourceManager.h" #include "TServer.h" -#include "TUDPServer.h" -#include #include #ifdef __unix @@ -52,11 +51,9 @@ int main(int argc, char** argv) { TResourceManager ResourceManager; TPPSMonitor PPSMonitor(Server); THeartbeatThread Heartbeat(ResourceManager, Server); - TTCPServer TCPServer(Server, PPSMonitor, ResourceManager); - TUDPServer UDPServer(Server, PPSMonitor, TCPServer); - TLuaEngine LuaEngine(Server, TCPServer, UDPServer); - TCPServer.SetUDPServer(UDPServer); - PPSMonitor.SetTCPServer(TCPServer); + TNetwork Network(Server, PPSMonitor, ResourceManager); + TLuaEngine LuaEngine(Server, Network); + PPSMonitor.SetNetwork(Network); Application::Console().InitializeLuaConsole(LuaEngine); // TODO: replace