From 88b0d108a4a24da956661c938d15f9fb4d5afeb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20G=C3=B6thel?= Date: Fri, 8 Nov 2024 05:43:45 +0100 Subject: [PATCH] net::Defaults.maxTCPConnections: Use system's maximum concurrent TCP connections, disable if undefined or below threshold MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Used system value on a Linux kernel are - /proc/sys/net/ipv4/tcp_max_orphans See https://www.kernel.org/doc/html/latest/networking/ip-sysctl.html - /proc/sys/net/nf_conntrack_max See https://www.kernel.org/doc/html/latest/networking/nf_conntrack-sysctl.html Value is memory bound. On GNU/Linux approximately 4 concurrent TCP connections per MB system memory are provided, e.g. {4096M -> 16384}, {16384M -> 65536}, {65407M -> 262144}, ... Signed-off-by: Sven Göthel Change-Id: Iad74f253bdac5636757b130b299b5deacda658db --- common/Util-desktop.cpp | 51 +++++++++++++++++++++++++++++++++++++++++ common/Util-mobile.cpp | 1 + common/Util.hpp | 4 ++++ net/Socket.cpp | 2 +- wsd/COOLWSD.cpp | 2 ++ 5 files changed, 59 insertions(+), 1 deletion(-) diff --git a/common/Util-desktop.cpp b/common/Util-desktop.cpp index bec440cf85f57..242d92c952496 100644 --- a/common/Util-desktop.cpp +++ b/common/Util-desktop.cpp @@ -9,6 +9,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include +#include #include "Util.hpp" @@ -160,6 +161,56 @@ std::size_t getTotalSystemMemoryKb() return totalMemKb; } +size_t getMaxConcurrentTCPConnections(const size_t minimum) +{ +#ifdef __linux__ + auto readDecimal = [](const char* path, const size_t defaultValue) -> size_t { + const int fd = ::open(path, O_RDONLY); + if (fd<0) + return defaultValue; + char data[1024+1]; // includes EOS + ::memset(data, 0, sizeof(data)); + size_t consumed = 0; + while (sizeof(data)-consumed-1 /* ex-EOS */ > 0) + { + ssize_t n; + while ((n = ::read(fd, data+consumed, sizeof(data)-consumed-1 /* ex-EOS */)) < 0 && errno == EINTR) {} + if (n < 0) // Error + { + consumed = 0; + break; + } + else if (n == 0) // EOF + break; + consumed += size_t(n); + } + ::close(fd); + if (consumed==0) + return defaultValue; + char* endptr = nullptr; + errno = 0; // Flush previous error indicator. Reminder: errno is thread-local + const unsigned long long num = std::strtoull(data, &endptr, 10); + if (0 != errno || nullptr == endptr || endptr == data ) + return defaultValue; + return size_t(num); + }; + // - 4 tcp_max_orphans sockets per MB + // - {4096M -> 16384}, {16384M -> 65536}, {65407M -> 262144}, ... + const ssize_t tcp_max_orphans = readDecimal("/proc/sys/net/ipv4/tcp_max_orphans", 0); // ignored if n/a + const ssize_t nf_conntrack_max = readDecimal("/proc/sys/net/nf_conntrack_max", 0); // ignored if n/a + const size_t res1 = nf_conntrack_max > 0 ? std::min(tcp_max_orphans, nf_conntrack_max) : tcp_max_orphans; + const size_t res2 = res1 >= minimum ? res1 : 0; + LOG_DBG("MaxConcurrentTCPConnections: clip(min(orphans " << tcp_max_orphans + << ", conntrack " << nf_conntrack_max << ") -> " + << res1 + << ", minimum " << minimum + << ") -> " << res2); + return res2; +#else + return 0; +#endif +} + std::size_t getFromCGroup(const std::string& group, const std::string& key) { std::size_t num = 0; diff --git a/common/Util-mobile.cpp b/common/Util-mobile.cpp index 5271422398e2c..0c3e9fb5f2876 100644 --- a/common/Util-mobile.cpp +++ b/common/Util-mobile.cpp @@ -21,6 +21,7 @@ int spawnProcess(const std::string& cmd, const StringVector& args) { return 0; } std::string getHumanizedBytes(unsigned long nBytes) { return std::string(); } size_t getTotalSystemMemoryKb() { return 0; } +size_t getMaxConcurrentTCPConnections(const size_t /*enabled_minimum*/) { return 0; } std::size_t getFromFile(const char* path) { return 0; } std::size_t getCGroupMemLimit() { return 0; } std::size_t getCGroupMemSoftLimit() { return 0; } diff --git a/common/Util.hpp b/common/Util.hpp index 9f224d0e16f1f..d04510394f865 100644 --- a/common/Util.hpp +++ b/common/Util.hpp @@ -333,6 +333,10 @@ namespace Util /// Returns the total physical memory (in kB) available in the system size_t getTotalSystemMemoryKb(); + /// Returns the maximum number of concurrent TCP connections, zero if undefined or less than given `minimum`. + /// Value is memory bound. On GNU/Linux approximately 4 concurrent TCP connections per MB system memory are provided. + size_t getMaxConcurrentTCPConnections(const size_t minimum); + /// Returns the numerical content of a file at @path std::size_t getFromFile(const char *path); diff --git a/net/Socket.cpp b/net/Socket.cpp index 568a6b99a94e8..f2c17c3112a89 100644 --- a/net/Socket.cpp +++ b/net/Socket.cpp @@ -70,7 +70,7 @@ std::unique_ptr SocketPoll::PollWatchdog; std::atomic StreamSocket::ExternalConnectionCount = 0; net::DefaultValues net::Defaults = { .inactivityTimeout = std::chrono::seconds(3600), - .maxExtConnections = 200000 /* arbitrary value to be resolved */ }; + .maxExtConnections = 0 /* disabled by default */}; #define SOCKET_ABSTRACT_UNIX_NAME "0coolwsd-" diff --git a/wsd/COOLWSD.cpp b/wsd/COOLWSD.cpp index ecff8b377b10e..4d99e78ad2220 100644 --- a/wsd/COOLWSD.cpp +++ b/wsd/COOLWSD.cpp @@ -2392,6 +2392,8 @@ void COOLWSD::innerInitialize(Poco::Util::Application& self) } UnitWSD::get().setWSD(this); + net::Defaults.maxExtConnections = Util::getMaxConcurrentTCPConnections(std::max(3, MAX_CONNECTIONS)); + // Allow UT to manipulate before using configuration values. UnitWSD::get().configure(conf);