Skip to content

Commit

Permalink
net::Defaults.maxTCPConnections: Use system's maximum concurrent TCP …
Browse files Browse the repository at this point in the history
…connections, disable if undefined or below threshold

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 <[email protected]>
Change-Id: Iad74f253bdac5636757b130b299b5deacda658db
  • Loading branch information
Sven Göthel authored and caolanm committed Nov 11, 2024
1 parent 9b7cf4a commit e97b802
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 1 deletion.
51 changes: 51 additions & 0 deletions common/Util-desktop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include <config.h>
#include <fcntl.h>

#include "Util.hpp"

Expand Down Expand Up @@ -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)

Check failure

Code scanning / CodeQL

Unsigned difference expression compared to zero Critical

Unsigned subtraction can never be negative.
{
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;
Expand Down
1 change: 1 addition & 0 deletions common/Util-mobile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
4 changes: 4 additions & 0 deletions common/Util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion net/Socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ std::unique_ptr<Watchdog> SocketPoll::PollWatchdog;
std::atomic<size_t> 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-"

Expand Down
2 changes: 2 additions & 0 deletions wsd/COOLWSD.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1514,6 +1514,8 @@ void COOLWSD::innerInitialize(Poco::Util::Application& self)
}
UnitWSD::get().setWSD(this);

net::Defaults.maxExtConnections = Util::getMaxConcurrentTCPConnections(std::max<size_t>(3, MAX_CONNECTIONS));

// Allow UT to manipulate before using configuration values.
UnitWSD::get().configure(conf);

Expand Down

0 comments on commit e97b802

Please sign in to comment.