From abb824d8235f3d2cc771ee1fefbf85445c3e3940 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20G=C3=B6thel?= Date: Tue, 29 Oct 2024 15:40:21 +0100 Subject: [PATCH] cool#9833: Adding net::Defaults to UT limited connections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using runtime mutable defaults for network properties allows us to test the connection limitation code. Costs are removal of constexpr properties, using a global instance, hence rendering the code less optimized and more pessimistic. Signed-off-by: Sven Göthel Change-Id: I5172b4067598c02678dd0cd2f56c0574013623d1 --- common/Unit.hpp | 1 - net/NetUtil.hpp | 16 ++++++++++++++++ net/Socket.cpp | 20 +++++++++++++------- net/Socket.hpp | 2 -- net/WebSocketHandler.hpp | 17 +++++++---------- test/UnitTimeoutConnections.cpp | 27 +++++++++++---------------- test/UnitTimeoutWSPing.cpp | 18 +++++++----------- wsd/COOLWSD.cpp | 8 +++++++- wsd/DocumentBroker.cpp | 2 +- 9 files changed, 62 insertions(+), 49 deletions(-) diff --git a/common/Unit.hpp b/common/Unit.hpp index 9584e452c4013..21e0cd7ebe048 100644 --- a/common/Unit.hpp +++ b/common/Unit.hpp @@ -7,7 +7,6 @@ #pragma once -#include #include #include #include diff --git a/net/NetUtil.hpp b/net/NetUtil.hpp index 124a8b31238c2..ebf2c25f59d8f 100644 --- a/net/NetUtil.hpp +++ b/net/NetUtil.hpp @@ -11,6 +11,7 @@ #pragma once +#include #include #include #include @@ -28,6 +29,21 @@ struct sockaddr; namespace net { +class DefaultValues +{ +public: + /// StreamSocket inactivity timeout in us (3600s default). Zero disables instrument. + std::chrono::microseconds inactivityTimeout; + /// WebSocketHandler average ping timeout in us (12s default). Zero disables instrument. + std::chrono::microseconds wsPingAvgTimeout; + /// WebSocketHandler ping interval in us (18s default), i.e. duration until next ping. Zero disables instrument. + std::chrono::microseconds wsPingInterval; + + /// Maximum number of concurrent TCP connections. Zero disables instrument. + size_t maxTCPConnections; +}; +extern DefaultValues Defaults; + class HostEntry { std::string _requestName; diff --git a/net/Socket.cpp b/net/Socket.cpp index 73b06093a77d2..0d75f84140c65 100644 --- a/net/Socket.cpp +++ b/net/Socket.cpp @@ -51,8 +51,8 @@ #include #endif #include "WebSocketHandler.hpp" -#include -#include +#include "net/HttpRequest.hpp" +#include "net/NetUtil.hpp" #include #include #include @@ -60,7 +60,6 @@ // Bug in pre C++17 where static constexpr must be defined. Fixed in C++17. constexpr std::chrono::microseconds SocketPoll::DefaultPollTimeoutMicroS; constexpr std::chrono::microseconds WebSocketHandler::InitialPingDelayMicroS; -constexpr std::chrono::microseconds WebSocketHandler::PingFrequencyMicroS; std::atomic SocketPoll::InhibitThreadChecks(false); std::atomic Socket::InhibitThreadChecks(false); @@ -70,6 +69,11 @@ std::unique_ptr SocketPoll::PollWatchdog; std::mutex SocketPoll::StatsMutex; std::atomic SocketPoll::StatsConnectionCount(0); +net::DefaultValues net::Defaults = { .inactivityTimeout = std::chrono::seconds(3600), + .wsPingAvgTimeout = std::chrono::seconds(12), + .wsPingInterval = std::chrono::seconds(18), + .maxTCPConnections = 200000 /* arbitrary value to be resolved */ }; + size_t SocketPoll::StatsConnectionMod(size_t added, size_t removed) { if( added == 0 && removed == 0 ) { return GetStatsConnectionCount(); @@ -316,6 +320,8 @@ namespace { SocketPoll::SocketPoll(std::string threadName) : _name(std::move(threadName)), + _limitedConnections( false ), + _connectionLimit( 0 ), _pollStartIndex(0), _stop(false), _threadStarted(0), @@ -1487,10 +1493,10 @@ bool StreamSocket::checkRemoval(std::chrono::steady_clock::time_point now) // Forced removal on outside-facing IPv[46] network connections only const auto durLast = std::chrono::duration_cast(now - getLastSeenTime()); - /// TO Criteria: Violate maximum idle (DefaultInactivityimeoutMicroS default 3600s) - const bool isInactive = SocketPoll::DefaultInactivityimeoutMicroS > std::chrono::microseconds::zero() && - durLast > SocketPoll::DefaultInactivityimeoutMicroS; - /// TO Criteria: Shall terminate? + /// Timeout criteria: Violate maximum inactivity (default 3600s) + const bool isInactive = net::Defaults.inactivityTimeout > std::chrono::microseconds::zero() && + durLast > net::Defaults.inactivityTimeout; + /// Timeout criteria: Shall terminate? const bool isTermination = SigUtil::getTerminationFlag(); if (isInactive || isTermination ) { diff --git a/net/Socket.hpp b/net/Socket.hpp index c15f62ede9dd6..8e254412b3cfb 100644 --- a/net/Socket.hpp +++ b/net/Socket.hpp @@ -715,8 +715,6 @@ class SocketPoll /// Default poll time - useful to increase for debugging. static constexpr std::chrono::microseconds DefaultPollTimeoutMicroS = std::chrono::seconds(64); - static constexpr std::chrono::microseconds DefaultInactivityimeoutMicroS = std::chrono::seconds(3600); - static constexpr size_t DefaultMaxTCPConnections = 200000; // arbitrary value to be resolved static std::atomic InhibitThreadChecks; /// Stop the polling thread. diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp index 8cafda66fc6f2..524fa4ad54825 100644 --- a/net/WebSocketHandler.hpp +++ b/net/WebSocketHandler.hpp @@ -13,7 +13,6 @@ #include "NetUtil.hpp" #include "Socket.hpp" -#include "common/Common.hpp" #include "common/Log.hpp" #include "common/Protocol.hpp" #include "common/Unit.hpp" @@ -62,8 +61,6 @@ class WebSocketHandler : public ProtocolHandlerInterface }; static constexpr std::chrono::microseconds InitialPingDelayMicroS = std::chrono::milliseconds(25); - static constexpr std::chrono::microseconds PingFrequencyMicroS = std::chrono::seconds(18); - static constexpr std::chrono::microseconds PingTimeoutMicroS = std::chrono::seconds(12); public: /// Perform upgrade ourselves, or select a client web socket. @@ -75,7 +72,7 @@ class WebSocketHandler : public ProtocolHandlerInterface : #if !MOBILEAPP _lastPingSentTime(std::chrono::steady_clock::now() - - PingFrequencyMicroS + + net::Defaults.wsPingInterval + std::chrono::microseconds(InitialPingDelayMicroS)) , _isMasking(isClient && isMasking) , _inFragmentBlock(false) @@ -603,7 +600,7 @@ class WebSocketHandler : public ProtocolHandlerInterface const auto timeSincePingMicroS = std::chrono::duration_cast(now - _lastPingSentTime); timeoutMaxMicroS - = std::min(timeoutMaxMicroS, (int64_t)(PingFrequencyMicroS - timeSincePingMicroS).count()); + = std::min(timeoutMaxMicroS, (int64_t)(net::Defaults.wsPingInterval - timeSincePingMicroS).count()); } #endif int events = POLLIN; @@ -670,21 +667,21 @@ class WebSocketHandler : public ProtocolHandlerInterface if (_isClient) return false; - if (PingTimeoutMicroS.count() > std::numeric_limits::epsilon() && - _pingMicroS.average() >= PingTimeoutMicroS.count()) + if (net::Defaults.wsPingAvgTimeout > std::chrono::microseconds::zero() && + _pingMicroS.average() >= net::Defaults.wsPingAvgTimeout.count()) { std::shared_ptr socket = _socket.lock(); if (socket && socket->isIPType()) // Exclude non-IP local sockets { LOG_WRN("CheckTimeout: Timeout websocket: Ping: last " << _pingMicroS.last() << "us, avg " - << _pingMicroS.average() << "us >= " << PingTimeoutMicroS.count() << "us over " + << _pingMicroS.average() << "us >= " << net::Defaults.wsPingAvgTimeout.count() << "us over " << (int)_pingMicroS.duration() << "s, " << *socket); shutdownSilent(socket); return true; } } - if (!_pingMicroS.initialized() || (PingFrequencyMicroS > std::chrono::microseconds::zero() && - now - _pingMicroS.lastTime() >= PingFrequencyMicroS)) + if (!_pingMicroS.initialized() || (net::Defaults.wsPingInterval > std::chrono::microseconds::zero() && + now - _pingMicroS.lastTime() >= net::Defaults.wsPingInterval)) { const std::shared_ptr socket = _socket.lock(); if (socket) diff --git a/test/UnitTimeoutConnections.cpp b/test/UnitTimeoutConnections.cpp index f99cc5f5f0358..1ead7df0d2224 100644 --- a/test/UnitTimeoutConnections.cpp +++ b/test/UnitTimeoutConnections.cpp @@ -34,8 +34,7 @@ class UnitTimeoutConnections : public UnitTimeoutBase1 { void configure(Poco::Util::LayeredConfiguration& /* config */) override { - // to be resolved! - // defaults.MaxConnections = ConnectionLimit; + net::Defaults.maxTCPConnections = ConnectionLimit; } public: @@ -49,24 +48,20 @@ class UnitTimeoutConnections : public UnitTimeoutBase1 void UnitTimeoutConnections::invokeWSDTest() { - // to be resolved! - if( false ) - { - UnitBase::TestResult result = TestResult::Ok; + UnitBase::TestResult result = TestResult::Ok; - result = testHttp(ConnectionLimit, ConnectionCount); - if (result != TestResult::Ok) - exitTest(result); + result = testHttp(ConnectionLimit, ConnectionCount); + if (result != TestResult::Ok) + exitTest(result); - result = testWSPing(ConnectionLimit, ConnectionCount); - if (result != TestResult::Ok) - exitTest(result); + result = testWSPing(ConnectionLimit, ConnectionCount); + if (result != TestResult::Ok) + exitTest(result); - result = testWSDChatPing(ConnectionLimit, ConnectionCount); - if (result != TestResult::Ok) - exitTest(result); + result = testWSDChatPing(ConnectionLimit, ConnectionCount); + if (result != TestResult::Ok) + exitTest(result); - } exitTest(TestResult::Ok); } diff --git a/test/UnitTimeoutWSPing.cpp b/test/UnitTimeoutWSPing.cpp index 65fc55b925fde..00c925d8851ad 100644 --- a/test/UnitTimeoutWSPing.cpp +++ b/test/UnitTimeoutWSPing.cpp @@ -34,9 +34,8 @@ class UnitTimeoutWSPing : public UnitTimeoutBase0 void configure(Poco::Util::LayeredConfiguration& /* config */) override { - // to be resolved! - // defaults.WSPingTimeout = std::chrono::microseconds(20); - // defaults.WSPingPeriod = std::chrono::microseconds(10000); + net::Defaults.wsPingAvgTimeout = std::chrono::microseconds(20); + net::Defaults.wsPingInterval = std::chrono::milliseconds(10); } public: @@ -82,15 +81,12 @@ UnitBase::TestResult UnitTimeoutWSPing::testWSPing() void UnitTimeoutWSPing::invokeWSDTest() { - // to be resolved! - if( false ) - { - UnitBase::TestResult result = TestResult::Ok; + UnitBase::TestResult result; + + result = testWSPing(); + if (result != TestResult::Ok) + exitTest(result); - result = testWSPing(); - if (result != TestResult::Ok) - exitTest(result); - } exitTest(TestResult::Ok); } diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 84e634244c92b..cac889b731317 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -2758,6 +2758,12 @@ void COOLWSD::innerInitialize(Poco::Util::Application& self) COOLWSD::MaxDocuments = MAX_DOCUMENTS; } #endif + { + LOG_DBG("net::Defaults: WSPing[timeout " + << net::Defaults.wsPingAvgTimeout << ", interval " << net::Defaults.wsPingInterval + << "], Socket[inactivityTimeout " << net::Defaults.inactivityTimeout + << ", maxTCPConnections " << net::Defaults.maxTCPConnections << "]"); + } #if !MOBILEAPP NoSeccomp = Util::isKitInProcess() || !getConfigValue(conf, "security.seccomp", true); @@ -2929,7 +2935,7 @@ void COOLWSD::innerInitialize(Poco::Util::Application& self) #endif WebServerPoll = std::make_unique("websrv_poll"); - WebServerPoll->setLimiter( SocketPoll::DefaultMaxTCPConnections ); + WebServerPoll->setLimiter( net::Defaults.maxTCPConnections ); #if !MOBILEAPP net::AsyncDNS::startAsyncDNS(); diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp index 817aced1d5715..e834b0b463a2e 100644 --- a/wsd/DocumentBroker.cpp +++ b/wsd/DocumentBroker.cpp @@ -139,7 +139,7 @@ class DocumentBroker::DocumentBrokerPoll final : public TerminatingPoll TerminatingPoll(threadName), _docBroker(docBroker) { - setLimiter( SocketPoll::DefaultMaxTCPConnections ); + setLimiter( net::Defaults.maxTCPConnections ); } void pollingThread() override