diff --git a/include/TConnectionLimiter.h b/include/TConnectionLimiter.h index ab70fa5..62df05f 100644 --- a/include/TConnectionLimiter.h +++ b/include/TConnectionLimiter.h @@ -8,6 +8,15 @@ class TConnectionLimiter { public: + struct TStats { + size_t CurrentGlobal = 0; + size_t MaxGlobal = 0; + size_t ActiveIpBuckets = 0; + size_t CurrentMaxPerIp = 0; + size_t MaxPerIp = 0; + size_t SaturatedIpBuckets = 0; + }; + class TGuard { public: TGuard() = default; @@ -36,6 +45,7 @@ public: TConnectionLimiter(size_t maxPerIp, size_t maxGlobal); [[nodiscard]] std::optional TryAcquire(const std::string& ip); + [[nodiscard]] TStats GetStats(); private: void Release(const std::string& ip) { diff --git a/include/TNetwork.h b/include/TNetwork.h index d1391b4..0d3df81 100644 --- a/include/TNetwork.h +++ b/include/TNetwork.h @@ -48,6 +48,7 @@ public: void SendToAll(TClient* c, const std::vector& Data, bool Self, bool Rel); void UpdatePlayer(TClient& Client); boost::system::error_code ReadWithTimeout(TConnection& Connection, void* Buf, size_t Len, std::chrono::steady_clock::duration Timeout); + [[nodiscard]] TConnectionLimiter::TStats GetConnectionLimiterStats() { return mConnectionLimiter.GetStats(); } TResourceManager& ResourceManager() const { return mResourceManager; } diff --git a/src/TConnectionLimiter.cpp b/src/TConnectionLimiter.cpp index 86e686b..8696963 100644 --- a/src/TConnectionLimiter.cpp +++ b/src/TConnectionLimiter.cpp @@ -32,6 +32,24 @@ std::optional TConnectionLimiter::TryAcquire(const s return TGuard(this, ip); } +TConnectionLimiter::TStats TConnectionLimiter::GetStats() { + std::unique_lock Lock { mMutex }; + TStats Stats; + Stats.CurrentGlobal = mGlobal; + Stats.MaxGlobal = mMaxGlobal; + Stats.ActiveIpBuckets = mPerIp.size(); + Stats.MaxPerIp = mMaxPerIp; + for (const auto& [_, Count] : mPerIp) { + if (Count > Stats.CurrentMaxPerIp) { + Stats.CurrentMaxPerIp = Count; + } + if (Count >= mMaxPerIp) { + ++Stats.SaturatedIpBuckets; + } + } + return Stats; +} + TConnectionLimiter::TGuard::TGuard(TConnectionLimiter* owner, std::string ip) : mOwner(owner) , mIp(std::move(ip)) { diff --git a/src/TConsole.cpp b/src/TConsole.cpp index fb1dc8b..317ec16 100644 --- a/src/TConsole.cpp +++ b/src/TConsole.cpp @@ -653,6 +653,7 @@ void TConsole::Command_Status(const std::string&, const std::vector SystemsShutdownList = SystemsShutdownList.substr(0, SystemsShutdownList.size() - 2); auto ElapsedTime = mLuaEngine->Server().UptimeTimer.GetElapsedTime(); + auto ConnectionLimiterStats = mLuaEngine->Network().GetConnectionLimiterStats(); Status << "BeamMP-Server Status:\n" << "\tTotal Players: " << mLuaEngine->Server().ClientCount() << "\n" @@ -667,6 +668,11 @@ void TConsole::Command_Status(const std::string&, const std::vector << "\t\tStates: " << mLuaEngine->GetLuaStateCount() << "\n" << "\t\tEvent timers: " << mLuaEngine->GetTimedEventsCount() << "\n" << "\t\tEvent handlers: " << mLuaEngine->GetRegisteredEventHandlerCount() << "\n" + << "\tConnection limiter:\n" + << "\t\tActive/Max global: " << ConnectionLimiterStats.CurrentGlobal << "/" << ConnectionLimiterStats.MaxGlobal << "\n" + << "\t\tActive IP buckets: " << ConnectionLimiterStats.ActiveIpBuckets << "\n" + << "\t\tHighest single IP load: " << ConnectionLimiterStats.CurrentMaxPerIp << "/" << ConnectionLimiterStats.MaxPerIp << "\n" + << "\t\tSaturated IP buckets: " << ConnectionLimiterStats.SaturatedIpBuckets << "\n" << "\tSubsystems:\n" << "\t\tGood/Starting/Bad: " << SystemsGood << "/" << SystemsStarting << "/" << SystemsBad << "\n" << "\t\tShutting down/Shut down: " << SystemsShuttingDown << "/" << SystemsShutdown << "\n"