diff --git a/common/Unit.hpp b/common/Unit.hpp index fa5d8e17007de..21e0cd7ebe048 100644 --- a/common/Unit.hpp +++ b/common/Unit.hpp @@ -7,7 +7,6 @@ #pragma once -#include #include #include #include @@ -17,7 +16,6 @@ #include #include "Util.hpp" -#include "NetUtil.hpp" #include "net/Socket.hpp" #include @@ -421,9 +419,6 @@ class UnitWSD : public UnitBase /// Manipulate and modify the configuration before any usage. virtual void configure(Poco::Util::LayeredConfiguration& /* config */) {} - /// Manipulate and modify the net::Defaults for before any usage. - virtual void configNet(net::Defaults& /* defaults */) {} - /// Main-loop reached, time for testing. /// Invoked from coolwsd's main thread. void invokeTest() diff --git a/kit/Kit.cpp b/kit/Kit.cpp index 36e85edf5308d..204c32809d631 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -68,7 +68,6 @@ #include #include "KitHelper.hpp" #include "Kit.hpp" -#include #include #include #include @@ -2928,7 +2927,7 @@ void documentViewCallback(const int type, const char* payload, void* data) int pollCallback(void* pData, int timeoutUs) { if (timeoutUs < 0) - timeoutUs = net::Defaults::get().SocketPollTimeout.count(); + timeoutUs = SocketPoll::DefaultPollTimeoutMicroS.count(); #ifndef IOS if (!pData) return 0; diff --git a/net/HttpRequest.hpp b/net/HttpRequest.hpp index 43b85df193c72..c98063443d257 100644 --- a/net/HttpRequest.hpp +++ b/net/HttpRequest.hpp @@ -1201,9 +1201,9 @@ class Session final : public ProtocolHandlerInterface } /// Returns the default timeout. - static std::chrono::milliseconds getDefaultTimeout() + static constexpr std::chrono::milliseconds getDefaultTimeout() { - return std::chrono::duration_cast( net::Defaults::get().HTTPTimeout ); + return std::chrono::seconds(30); } /// Returns the current protocol scheme. diff --git a/net/NetUtil.hpp b/net/NetUtil.hpp index 62458ae181c07..ebf2c25f59d8f 100644 --- a/net/NetUtil.hpp +++ b/net/NetUtil.hpp @@ -29,42 +29,20 @@ struct sockaddr; namespace net { -class Defaults +class DefaultValues { public: - /// WebSocketHandler ping timeout in us (2s default). Zero disables metric. - std::chrono::microseconds WSPingTimeout; - /// WebSocketHandler ping period in us (3s default), i.e. duration until next ping. Zero disables metric. - std::chrono::microseconds WSPingPeriod; - /// http::Session timeout in us (30s default). Zero disables metric. - std::chrono::microseconds HTTPTimeout; - - /// Maximum total connections (9999 or MAX_CONNECTIONS). Zero disables metric. - size_t MaxConnections; - - /// Socket poll timeout in us (64s), useful to increase for debugging. - std::chrono::microseconds SocketPollTimeout; - -private: - Defaults() - : WSPingTimeout(std::chrono::microseconds(2000000)) - , WSPingPeriod(std::chrono::microseconds(3000000)) - , HTTPTimeout(std::chrono::microseconds(30000000)) - , MaxConnections(9999) - , SocketPollTimeout(std::chrono::microseconds(64000000)) - { - } - -public: - Defaults(const Defaults&) = delete; - Defaults(Defaults&&) = delete; - - static Defaults& get() - { - static Defaults def; - return def; - } + /// 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 { diff --git a/net/Socket.cpp b/net/Socket.cpp index 447130742526a..364936ae364d3 100644 --- a/net/Socket.cpp +++ b/net/Socket.cpp @@ -57,6 +57,10 @@ #include #include +// 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; + std::atomic SocketPoll::InhibitThreadChecks(false); std::atomic Socket::InhibitThreadChecks(false); @@ -65,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(); @@ -190,7 +199,6 @@ bool StreamSocket::socketpair(const std::chrono::steady_clock::time_point &creat int rc = ::socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, pair); if (rc != 0) return false; - child = std::make_shared("save-child", pair[0], Socket::Type::Unix, true, HostType::Other, ReadType::NormalRead, creationTime); child->setNoShutdown(); child->setClientAddress("save-child"); @@ -312,7 +320,6 @@ namespace { SocketPoll::SocketPoll(std::string threadName) : _name(std::move(threadName)), - _pollTimeout( net::Defaults::get().SocketPollTimeout ), _limitedConnections( false ), _connectionLimit( 0 ), _pollStartIndex(0), @@ -1089,7 +1096,7 @@ void WebSocketHandler::dumpState(std::ostream& os, const std::string& /*indent*/ void StreamSocket::dumpState(std::ostream& os) { - int64_t timeoutMaxMicroS = _pollTimeout.count(); + int64_t timeoutMaxMicroS = SocketPoll::DefaultPollTimeoutMicroS.count(); const int events = getPollEvents(std::chrono::steady_clock::now(), timeoutMaxMicroS); os << '\t' << std::setw(6) << getFD() << "\t0x" << std::hex << events << std::dec << '\t' << (ignoringInput() ? "ignore\t" : "process\t") << std::setw(6) << _inBuffer.size() << '\t' @@ -1487,14 +1494,14 @@ 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 (_pollTimeout default 64s) - const bool isIdle = _pollTimeout > std::chrono::microseconds::zero() && - durLast > _pollTimeout; - /// 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 (isIdle || isTermination ) + if (isInactive || isTermination ) { - LOG_WRN("CheckRemoval: Timeout: {Idle " << isIdle + LOG_WRN("CheckRemoval: Timeout: {Inactive " << isInactive << ", Termination " << isTermination << "}, " << getStatsString(now) << ", " << *this); @@ -1529,8 +1536,8 @@ bool StreamSocket::parseHeader(const char *clientName, { assert(map._headerSize == 0 && map._messageSize == 0); - const std::chrono::duration delayMax = - std::chrono::duration_cast(_httpTimeout); + constexpr std::chrono::duration delayMax = + std::chrono::duration_cast(SocketPoll::DefaultPollTimeoutMicroS); std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now(); std::chrono::duration delayMs = now - lastHTTPHeader; diff --git a/net/Socket.hpp b/net/Socket.hpp index b5aa4acf88a2a..8e254412b3cfb 100644 --- a/net/Socket.hpp +++ b/net/Socket.hpp @@ -36,7 +36,6 @@ #include "Util.hpp" #include "Buffer.hpp" #include "SigUtil.hpp" -#include "NetUtil.hpp" #include "FakeSocket.hpp" @@ -714,6 +713,8 @@ class SocketPoll static std::unique_ptr PollWatchdog; + /// Default poll time - useful to increase for debugging. + static constexpr std::chrono::microseconds DefaultPollTimeoutMicroS = std::chrono::seconds(64); static std::atomic InhibitThreadChecks; /// Stop the polling thread. @@ -947,7 +948,7 @@ class SocketPoll { while (continuePolling()) { - poll(_pollTimeout); + poll(DefaultPollTimeoutMicroS); } } @@ -999,7 +1000,6 @@ class SocketPoll /// Debug name used for logging. const std::string _name; - const std::chrono::microseconds _pollTimeout; bool _limitedConnections; size_t _connectionLimit; @@ -1067,8 +1067,6 @@ class StreamSocket : public Socket, HostType hostType, ReadType readType = ReadType::NormalRead, std::chrono::steady_clock::time_point creationTime = std::chrono::steady_clock::now() ) : Socket(fd, type, creationTime), - _pollTimeout( net::Defaults::get().SocketPollTimeout ), - _httpTimeout( net::Defaults::get().HTTPTimeout ), _hostname(std::move(host)), _wsState(WSState::HTTP), _isLocalHost(hostType == LocalHost), @@ -1749,11 +1747,6 @@ class StreamSocket : public Socket, #endif private: - /// default to 64s, see net::Defaults::SocketPollTimeout - const std::chrono::microseconds _pollTimeout; - /// defaults to 30s, see net::Defaults::HTTPTimeout - const std::chrono::microseconds _httpTimeout; - /// The hostname (or IP) of the peer we are connecting to. const std::string _hostname; diff --git a/net/WebSocketHandler.hpp b/net/WebSocketHandler.hpp index efe8c1bed6b59..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" @@ -35,8 +34,6 @@ class WebSocketHandler : public ProtocolHandlerInterface std::weak_ptr _socket; #if !MOBILEAPP - std::chrono::microseconds _pingPeriod; - std::chrono::duration _pingTimeout; std::chrono::steady_clock::time_point _lastPingSentTime; Util::TimeAverage _pingMicroS; bool _isMasking; @@ -74,10 +71,8 @@ class WebSocketHandler : public ProtocolHandlerInterface WebSocketHandler(bool isClient, [[maybe_unused]] bool isMasking) : #if !MOBILEAPP - _pingPeriod(net::Defaults::get().WSPingPeriod), - _pingTimeout(net::Defaults::get().WSPingTimeout), _lastPingSentTime(std::chrono::steady_clock::now() - - _pingPeriod + + net::Defaults.wsPingInterval + std::chrono::microseconds(InitialPingDelayMicroS)) , _isMasking(isClient && isMasking) , _inFragmentBlock(false) @@ -605,7 +600,7 @@ class WebSocketHandler : public ProtocolHandlerInterface const auto timeSincePingMicroS = std::chrono::duration_cast(now - _lastPingSentTime); timeoutMaxMicroS - = std::min(timeoutMaxMicroS, (int64_t)(_pingPeriod - timeSincePingMicroS).count()); + = std::min(timeoutMaxMicroS, (int64_t)(net::Defaults.wsPingInterval - timeSincePingMicroS).count()); } #endif int events = POLLIN; @@ -672,21 +667,21 @@ class WebSocketHandler : public ProtocolHandlerInterface if (_isClient) return false; - if (_pingTimeout.count() > std::numeric_limits::epsilon() && - _pingMicroS.average() >= _pingTimeout.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 >= " << _pingTimeout.count() << "us over " + << _pingMicroS.average() << "us >= " << net::Defaults.wsPingAvgTimeout.count() << "us over " << (int)_pingMicroS.duration() << "s, " << *socket); shutdownSilent(socket); return true; } } - if (!_pingMicroS.initialized() || (_pingPeriod > std::chrono::microseconds::zero() && - now - _pingMicroS.lastTime() >= _pingPeriod)) + 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/UnitPerf.cpp b/test/UnitPerf.cpp index 26c57f9823cea..b1cc35b532e6f 100644 --- a/test/UnitPerf.cpp +++ b/test/UnitPerf.cpp @@ -57,8 +57,6 @@ void UnitPerf::testPerf(std::string testType, std::string fileType, std::string stats = std::make_shared(); stats->setTypeOfTest(std::move(testType)); - const std::chrono::microseconds PollTimeoutMicroS = net::Defaults::get().SocketPollTimeout; - TerminatingPoll poll("performance test"); std::string docName = "empty." + fileType; @@ -74,7 +72,7 @@ void UnitPerf::testPerf(std::string testType, std::string fileType, std::string stats); do { - poll.poll(PollTimeoutMicroS); + poll.poll(TerminatingPoll::DefaultPollTimeoutMicroS); } while (poll.continuePolling() && poll.getSocketCount() > 0); stats->dump(); diff --git a/test/UnitTimeoutConnections.cpp b/test/UnitTimeoutConnections.cpp index 5d6f1839ce8bf..1ead7df0d2224 100644 --- a/test/UnitTimeoutConnections.cpp +++ b/test/UnitTimeoutConnections.cpp @@ -32,14 +32,9 @@ static constexpr size_t ConnectionCount = 9; /// Base test suite class for connection limit (limited) using HTTP and WS sessions. class UnitTimeoutConnections : public UnitTimeoutBase1 { - void configNet(net::Defaults& defaults) override + void configure(Poco::Util::LayeredConfiguration& /* config */) override { - // defaults.WSPingTimeout = std::chrono::microseconds(2000000); - // defaults.WSPingPeriod = std::chrono::microseconds(3000000); - // defaults.HTTPTimeout = std::chrono::microseconds(30000000); - // defaults.MaxConnections = 9999; - defaults.MaxConnections = ConnectionLimit; - // defaults.SocketPollTimeout = std::chrono::microseconds(64000000); + net::Defaults.maxTCPConnections = ConnectionLimit; } public: diff --git a/test/UnitTimeoutNone.cpp b/test/UnitTimeoutNone.cpp index 8ce994e75b521..d861f95ad393f 100644 --- a/test/UnitTimeoutNone.cpp +++ b/test/UnitTimeoutNone.cpp @@ -31,15 +31,9 @@ static constexpr size_t ConnectionCount = 9; /// Base test suite class for connection limit (no limits) using HTTP and WS sessions. class UnitTimeoutNone : public UnitTimeoutBase1 { - void configNet(net::Defaults& /* defaults */) override + void configure(Poco::Util::LayeredConfiguration& /* config */) override { // Keep original values -> No timeout - // defaults.WSPingTimeout = std::chrono::microseconds(2000000); - // defaults.WSPingPeriod = std::chrono::microseconds(3000000); - // defaults.HTTPTimeout = std::chrono::microseconds(30000000); - // defaults.MaxConnections = 9999; - // defaults.MaxConnections = ConnectionLimit; - // defaults.SocketPollTimeout = std::chrono::microseconds(64000000); } public: diff --git a/test/UnitTimeoutWSPing.cpp b/test/UnitTimeoutWSPing.cpp index 0f2fe34378bd2..00c925d8851ad 100644 --- a/test/UnitTimeoutWSPing.cpp +++ b/test/UnitTimeoutWSPing.cpp @@ -32,15 +32,10 @@ class UnitTimeoutWSPing : public UnitTimeoutBase0 { TestResult testWSPing(); - void configNet(net::Defaults& defaults) override + void configure(Poco::Util::LayeredConfiguration& /* config */) override { - // defaults.WSPingTimeout = std::chrono::microseconds(2000000); - // defaults.WSPingPeriod = std::chrono::microseconds(3000000); - defaults.WSPingTimeout = std::chrono::microseconds(20); - defaults.WSPingPeriod = std::chrono::microseconds(10000); - // defaults.HTTPTimeout = std::chrono::microseconds(30000000); - // defaults.MaxConnections = 9999; - // defaults.SocketPollTimeout = std::chrono::microseconds(64000000); + net::Defaults.wsPingAvgTimeout = std::chrono::microseconds(20); + net::Defaults.wsPingInterval = std::chrono::milliseconds(10); } public: @@ -90,7 +85,7 @@ void UnitTimeoutWSPing::invokeWSDTest() result = testWSPing(); if (result != TestResult::Ok) - exitTest(result); + exitTest(result); exitTest(TestResult::Ok); } diff --git a/tools/Stress.cpp b/tools/Stress.cpp index c56c02ec4aab4..f72f5c73e205c 100644 --- a/tools/Stress.cpp +++ b/tools/Stress.cpp @@ -89,9 +89,7 @@ int Stress::main(const std::vector& args) } #endif - const std::chrono::microseconds PollTimeoutMicroS = net::Defaults::get().SocketPollTimeout; - - const std::string& server = args[0]; + std::string server = args[0]; if (!strncmp(server.c_str(), "http", 4)) { @@ -106,7 +104,7 @@ int Stress::main(const std::vector& args) StressSocketHandler::addPollFor(poll, server, args[i], args[i+1], stats); do { - poll.poll(PollTimeoutMicroS); + poll.poll(TerminatingPoll::DefaultPollTimeoutMicroS); } while (poll.continuePolling() && poll.getSocketCount() > 0); stats->dump(); diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index 89e09ad131042..cac889b731317 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -11,7 +11,6 @@ #include #include -#include #include "COOLWSD.hpp" #if ENABLE_FEATURE_LOCK @@ -2338,12 +2337,6 @@ void COOLWSD::innerInitialize(Poco::Util::Application& self) // Allow UT to manipulate before using configuration values. UnitWSD::get().configure(conf); - // net::Defaults: Set MaxConnections field and allow UT to manipulate before using - { - net::Defaults& defaults = net::Defaults::get(); - net::Defaults::get().MaxConnections = std::max(3, MAX_CONNECTIONS); - UnitWSD::get().configNet(defaults); - } // Trace Event Logging. EnableTraceEventLogging = getConfigValue(conf, "trace_event[@enable]", false); @@ -2750,28 +2743,26 @@ void COOLWSD::innerInitialize(Poco::Util::Application& self) if (getConfigValue(conf, "home_mode.enable", false)) { COOLWSD::MaxConnections = 20; - net::Defaults::get().MaxConnections = COOLWSD::MaxConnections; // re-align COOLWSD::MaxDocuments = 10; } else { conf.setString("feedback.show", "true"); conf.setString("welcome.enable", "true"); - COOLWSD::MaxConnections = net::Defaults::get().MaxConnections; // aligned w/ MAX_CONNECTIONS above + COOLWSD::MaxConnections = MAX_CONNECTIONS; COOLWSD::MaxDocuments = MAX_DOCUMENTS; } #else { - COOLWSD::MaxConnections = net::Defaults::get().MaxConnections; // aligned w/ MAX_CONNECTIONS above + COOLWSD::MaxConnections = MAX_CONNECTIONS; COOLWSD::MaxDocuments = MAX_DOCUMENTS; } #endif { - net::Defaults& netDefaults = net::Defaults::get(); - LOG_DBG("net::Defaults: WSPing[Timeout " - << netDefaults.WSPingTimeout << ", Period " << netDefaults.WSPingPeriod << "], HTTP[Timeout " - << netDefaults.HTTPTimeout << "], Socket[MaxConnections " << netDefaults.MaxConnections - << "], SocketPoll[Timeout " << netDefaults.SocketPollTimeout << "]"); + LOG_DBG("net::Defaults: WSPing[timeout " + << net::Defaults.wsPingAvgTimeout << ", interval " << net::Defaults.wsPingInterval + << "], Socket[inactivityTimeout " << net::Defaults.inactivityTimeout + << ", maxTCPConnections " << net::Defaults.maxTCPConnections << "]"); } #if !MOBILEAPP @@ -2944,7 +2935,7 @@ void COOLWSD::innerInitialize(Poco::Util::Application& self) #endif WebServerPoll = std::make_unique("websrv_poll"); - WebServerPoll->setLimiter( net::Defaults::get().MaxConnections ); + WebServerPoll->setLimiter( net::Defaults.maxTCPConnections ); #if !MOBILEAPP net::AsyncDNS::startAsyncDNS(); @@ -4550,12 +4541,11 @@ int COOLWSD::innerMain() #endif SigUtil::addActivity("coolwsd running"); - const std::chrono::microseconds PollTimeoutMicroS = net::Defaults::get().SocketPollTimeout; while (!SigUtil::getShutdownRequestFlag()) { // This timeout affects the recovery time of prespawned children. - std::chrono::microseconds waitMicroS = PollTimeoutMicroS * 4; + std::chrono::microseconds waitMicroS = SocketPoll::DefaultPollTimeoutMicroS * 4; if (UnitWSD::isUnitTesting() && !SigUtil::getShutdownRequestFlag()) { diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp index 6e7e1b7262bd5..e834b0b463a2e 100644 --- a/wsd/DocumentBroker.cpp +++ b/wsd/DocumentBroker.cpp @@ -38,7 +38,6 @@ #include "Exceptions.hpp" #include "COOLWSD.hpp" #include "FileServer.hpp" -#include #include "Socket.hpp" #include "Storage.hpp" #include "TileCache.hpp" @@ -140,7 +139,7 @@ class DocumentBroker::DocumentBrokerPoll final : public TerminatingPoll TerminatingPoll(threadName), _docBroker(docBroker) { - setLimiter( net::Defaults::get().MaxConnections ); + setLimiter( net::Defaults.maxTCPConnections ); } void pollingThread() override @@ -370,14 +369,14 @@ void DocumentBroker::pollThread() std::chrono::time_point migrationMsgStartTime; static const std::chrono::microseconds migrationMsgTimeout = std::chrono::seconds( COOLWSD::getConfigValue("indirection_endpoint.migration_timeout_secs", 180)); - const std::chrono::microseconds PollTimeoutMicroS = net::Defaults::get().SocketPollTimeout; // Main polling loop goodness. while (!_stop && _poll->continuePolling() && !SigUtil::getTerminationFlag()) { // Poll more frequently while unloading to cleanup sooner. const bool unloading = isMarkedToDestroy() || _docState.isUnloadRequested(); - _poll->poll(unloading ? PollTimeoutMicroS / 16 : PollTimeoutMicroS); + _poll->poll(unloading ? SocketPoll::DefaultPollTimeoutMicroS / 16 + : SocketPoll::DefaultPollTimeoutMicroS); // Consolidate updates across multiple processed events. processBatchUpdates();