diff --git a/CMakeLists.txt b/CMakeLists.txt index 27ff731..118e9b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -119,6 +119,7 @@ set(BeamMP_Sources include/ArgsParser.h src/ArgsParser.cpp include/TPluginMonitor.h src/TPluginMonitor.cpp include/Environment.h + include/BoostAliases.h ) set(BeamMP_Includes diff --git a/include/BoostAliases.h b/include/BoostAliases.h new file mode 100644 index 0000000..a42265b --- /dev/null +++ b/include/BoostAliases.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +using namespace boost::asio; diff --git a/include/Client.h b/include/Client.h index 114ff3e..fa70208 100644 --- a/include/Client.h +++ b/include/Client.h @@ -7,6 +7,7 @@ #include #include +#include "BoostAliases.h" #include "Common.h" #include "Compat.h" #include "VehicleData.h" @@ -46,14 +47,15 @@ public: void SetIdentifier(const std::string& key, const std::string& value) { mIdentifiers[key] = value; } std::string GetCarData(int Ident); std::string GetCarPositionRaw(int Ident); - void SetUDPAddr(sockaddr_in Addr) { mUDPAddress = Addr; } + void SetUDPAddr(const ip::udp::endpoint& Addr) { mUDPAddress = Addr; } void SetDownSock(SOCKET CSock) { mSocket[1] = CSock; } void SetTCPSock(SOCKET CSock) { mSocket[0] = CSock; } void SetStatus(int Status) { mStatus = Status; } // locks void DeleteCar(int Ident); [[nodiscard]] const std::unordered_map& GetIdentifiers() const { return mIdentifiers; } - [[nodiscard]] sockaddr_in GetUDPAddr() const { return mUDPAddress; } + [[nodiscard]] const ip::udp::endpoint& GetUDPAddr() const { return mUDPAddress; } + [[nodiscard]] ip::udp::endpoint& GetUDPAddr() { return mUDPAddress; } [[nodiscard]] SOCKET GetDownSock() const { return mSocket[1]; } [[nodiscard]] SOCKET GetTCPSock() const { return mSocket[0]; } [[nodiscard]] std::string GetRoles() const { return mRole; } @@ -100,7 +102,7 @@ private: SparseArray mVehiclePosition; std::string mName = "Unknown Client"; SOCKET mSocket[2] { SOCKET(0), SOCKET(0) }; - sockaddr_in mUDPAddress {}; // is this initialization OK? yes it is + ip::udp::endpoint mUDPAddress {}; int mUnicycleID = -1; std::string mRole; std::string mDID; diff --git a/include/TNetwork.h b/include/TNetwork.h index 6394306..f18f17f 100644 --- a/include/TNetwork.h +++ b/include/TNetwork.h @@ -1,8 +1,11 @@ #pragma once +#include "BoostAliases.h" #include "Compat.h" #include "TResourceManager.h" #include "TServer.h" +#include +#include struct TConnection; @@ -21,7 +24,7 @@ public: void Authentication(const TConnection& ClientConnection); [[nodiscard]] bool CheckBytes(TClient& c, int32_t BytesRcv); void SyncResources(TClient& c); - [[nodiscard]] bool UDPSend(TClient& Client, std::string Data) const; + [[nodiscard]] bool UDPSend(TClient& Client, std::string Data); void SendToAll(TClient* c, const std::string& Data, bool Self, bool Rel); void UpdatePlayer(TClient& Client); @@ -31,12 +34,13 @@ private: TServer& mServer; TPPSMonitor& mPPSMonitor; - SOCKET mUDPSock {}; + io_context mIoCtx; + ip::udp::socket mUDPSock; TResourceManager& mResourceManager; std::thread mUDPThread; std::thread mTCPThread; - std::string UDPRcvFromClient(sockaddr_in& client) const; + std::string UDPRcvFromClient(ip::udp::endpoint& ClientEndpoint); void HandleDownload(SOCKET TCPSock); void OnConnect(const std::weak_ptr& c); void TCPClient(const std::weak_ptr& c); diff --git a/src/TNetwork.cpp b/src/TNetwork.cpp index 588834d..3349e33 100644 --- a/src/TNetwork.cpp +++ b/src/TNetwork.cpp @@ -5,11 +5,15 @@ #include #include #include +#include +#include #include TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& ResourceManager) : mServer(Server) , mPPSMonitor(PPSMonitor) + , mIoCtx {} + , mUDPSock(mIoCtx) , mResourceManager(ResourceManager) { Application::SetSubsystemStatus("TCPNetwork", Application::Status::Starting); Application::SetSubsystemStatus("UDPNetwork", Application::Status::Starting); @@ -42,40 +46,25 @@ TNetwork::TNetwork(TServer& Server, TPPSMonitor& PPSMonitor, TResourceManager& R void TNetwork::UDPServerMain() { RegisterThread("UDPServer"); -#if defined(BEAMMP_WINDOWS) - WSADATA data; - if (WSAStartup(514, &data)) { - beammp_error(("Can't start Winsock!")); - // return; - } -#endif // WINDOWS - 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, reinterpret_cast(&serverAddr), sizeof(serverAddr)) != 0) { + mUDPSock = ip::udp::socket(mIoCtx); + ip::udp::endpoint UdpListenEndpoint(ip::udp::v4(), Application::Settings.Port); + boost::system::error_code ec; + mUDPSock.bind(UdpListenEndpoint, ec); + if (ec) { beammp_error("bind() failed: " + GetPlatformAgnosticErrorString()); std::this_thread::sleep_for(std::chrono::seconds(5)); - exit(-1); // TODO: Wtf. - // return; + Application::GracefullyShutdown(); } Application::SetSubsystemStatus("UDPNetwork", Application::Status::Good); beammp_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 (!Application::IsShuttingDown()) { try { - sockaddr_in client {}; + ip::udp::endpoint 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 { std::shared_ptr Client; @@ -995,7 +984,7 @@ void TNetwork::SendToAll(TClient* c, const std::string& Data, bool Self, bool Re return; } -bool TNetwork::UDPSend(TClient& Client, std::string Data) const { +bool TNetwork::UDPSend(TClient& Client, std::string Data) { 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 @@ -1003,28 +992,15 @@ bool TNetwork::UDPSend(TClient& Client, std::string Data) const { // this is fine can can be ignored :^) return true; } - sockaddr_in Addr = Client.GetUDPAddr(); - auto AddrSize = sizeof(Client.GetUDPAddr()); + const auto Addr = 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, reinterpret_cast(&Addr), int(AddrSize)); - if (sendOk == -1) { - beammp_debug("(UDP) sendto() failed: " + GetPlatformAgnosticErrorString()); - if (Client.GetStatus() > -1) - Client.SetStatus(-1); - return false; - } else if (sendOk == 0) { - beammp_debug(("(UDP) sendto() returned 0")); + boost::system::error_code ec; + mUDPSock.send_to(buffer(Data), Addr, 0, ec); + if (ec) { + beammp_debugf("UDP sendto() failed: {}", ec.what()); if (Client.GetStatus() > -1) Client.SetStatus(-1); return false; @@ -1032,18 +1008,14 @@ bool TNetwork::UDPSend(TClient& Client, std::string Data) const { return true; } -std::string TNetwork::UDPRcvFromClient(sockaddr_in& client) const { - size_t clientLength = sizeof(client); +std::string TNetwork::UDPRcvFromClient(ip::udp::endpoint& ClientEndpoint) { 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, reinterpret_cast(&client), reinterpret_cast(&clientLength)); -#endif // WIN32 - - if (Rcv == -1) { - beammp_error("(UDP) Error receiving from client! recvfrom() failed: " + GetPlatformAgnosticErrorString()); + boost::system::error_code ec; + const auto Rcv = mUDPSock.receive_from(mutable_buffer(Ret.data(), Ret.size()), ClientEndpoint, 0, ec); + if (ec) { + beammp_errorf("UDP recvfrom() failed: {}", ec.what()); return ""; } + // FIXME: This breaks binary data due to \0. return std::string(Ret.begin(), Ret.begin() + Rcv); }