|
40 | 40 | #include <limits.h> |
41 | 41 |
|
42 | 42 | #include <list> |
| 43 | +#include <filesystem> |
| 44 | +#include <sys/resource.h> |
43 | 45 |
|
44 | 46 | #include <Common/Daemon.h> |
45 | 47 | #include <Common/SimpleLog.h> |
@@ -67,7 +69,7 @@ class ConfigInfoLoggerD |
67 | 69 | std::string localLogDirectory = "/tmp/infoLoggerD"; // local directory to be used for log storage, whenever necessary |
68 | 70 | std::string rxSocketPath = INFOLOGGER_DEFAULT_LOCAL_SOCKET; // name of socket used to receive log messages from clients |
69 | 71 | int rxSocketInBufferSize = -1; // size of socket receiving buffer. -1 will leave to sys default. |
70 | | - int rxMaxConnections = 1024; // maximum number of incoming connections |
| 72 | + int rxMaxConnections = 2048; // maximum number of incoming connections |
71 | 73 |
|
72 | 74 | // settings for remote infoLoggerServer access |
73 | 75 | std::string serverHost = "localhost"; // IP name to connect infoLoggerServer |
@@ -217,6 +219,8 @@ class InfoLoggerD : public Daemon |
217 | 219 | TR_client_handle hCx = nullptr; // handle to server transport |
218 | 220 |
|
219 | 221 | FILE* logOutput = nullptr; // handle to local log file where to copy incoming messages, if configured to do so |
| 222 | + |
| 223 | + bool stateAcceptFailed = 0; // flag to keep track accept() failing, and avoid flooding log output with errors in case of e.g. reaching max number of open files |
220 | 224 | }; |
221 | 225 |
|
222 | 226 | // list of extra keys accepted on the command line (-o key=value entries) |
@@ -373,6 +377,58 @@ InfoLoggerD::InfoLoggerD(int argc, char* argv[]) : Daemon(argc, argv, nullptr, E |
373 | 377 | // todo: open a log file! |
374 | 378 | } |
375 | 379 |
|
| 380 | + // check consistency of settings for max number of incoming connections |
| 381 | + if (1) { |
| 382 | + log.info("Checking resources for rxMaxConnections = %d", configInfoLoggerD.rxMaxConnections); |
| 383 | + long fileDescriptorCount = 0; |
| 384 | + long fileDescriptorMax = 0; |
| 385 | + struct rlimit rlim; |
| 386 | + bool limitOk = 0; |
| 387 | + try { |
| 388 | + fileDescriptorCount = std::distance(std::filesystem::directory_iterator("/proc/self/fd"), std::filesystem::directory_iterator{}); |
| 389 | + log.info("At the moment, having %ld files opened", fileDescriptorCount); |
| 390 | + } |
| 391 | + catch(...) { |
| 392 | + } |
| 393 | + // iterate a couple of time to get/set rlimit if needed |
| 394 | + for (int i=0; i<2; i++) { |
| 395 | + int err = getrlimit(RLIMIT_NOFILE, &rlim); |
| 396 | + if (err) { |
| 397 | + log.error("getrlimit() failed: %s", strerror(errno)); |
| 398 | + break; |
| 399 | + } |
| 400 | + fileDescriptorMax = (long) rlim.rlim_cur; |
| 401 | + log.info("getrlimit(): soft = %lu, hard = %lu", (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max); |
| 402 | + if (fileDescriptorCount + configInfoLoggerD.rxMaxConnections > (long)rlim.rlim_cur) { |
| 403 | + log.info("Current limits are not compatible with rxMaxConnections = %d", configInfoLoggerD.rxMaxConnections); |
| 404 | + |
| 405 | + // trying to increase limits once |
| 406 | + if (i) break; |
| 407 | + rlim.rlim_cur = (unsigned long)(fileDescriptorCount + configInfoLoggerD.rxMaxConnections + 1); |
| 408 | + log.info("Trying to increase limit to %ld", (long)rlim.rlim_cur); |
| 409 | + if (rlim.rlim_cur > rlim.rlim_max) { |
| 410 | + rlim.rlim_cur = rlim.rlim_max; |
| 411 | + } |
| 412 | + err = setrlimit(RLIMIT_NOFILE, &rlim); |
| 413 | + if (err) { |
| 414 | + log.error("setrlimit() failed: %s", strerror(errno)); |
| 415 | + break; |
| 416 | + } |
| 417 | + } else { |
| 418 | + log.info("Limits ok, should be able to cope with %d max connections", configInfoLoggerD.rxMaxConnections); |
| 419 | + limitOk = 1; |
| 420 | + break; |
| 421 | + } |
| 422 | + } |
| 423 | + if (!limitOk) { |
| 424 | + configInfoLoggerD.rxMaxConnections = fileDescriptorMax - fileDescriptorCount - 1; |
| 425 | + if (configInfoLoggerD.rxMaxConnections <= 0) { |
| 426 | + configInfoLoggerD.rxMaxConnections = 1; |
| 427 | + } |
| 428 | + log.info("Reducing rxMaxConnections to %d", configInfoLoggerD.rxMaxConnections); |
| 429 | + } |
| 430 | + } |
| 431 | + |
376 | 432 | isInitialized = 1; |
377 | 433 | log.info("infoLoggerD started"); |
378 | 434 | } |
@@ -496,8 +552,15 @@ Daemon::LoopStatus InfoLoggerD::doLoop() |
496 | 552 | socklen_t socketAddressLen = sizeof(socketAddress); |
497 | 553 | int tmpSocket = accept(rxSocket, (struct sockaddr*)&socketAddress, &socketAddressLen); |
498 | 554 | if (tmpSocket == -1) { |
499 | | - log.error("accept() failed: %s", strerror(errno)); |
| 555 | + if (!stateAcceptFailed) { |
| 556 | + stateAcceptFailed = 1; |
| 557 | + log.error("accept() failed: %s", strerror(errno)); |
| 558 | + } |
500 | 559 | } else { |
| 560 | + if (stateAcceptFailed) { |
| 561 | + log.info("accept() failure now recovered"); |
| 562 | + stateAcceptFailed = 0; |
| 563 | + } |
501 | 564 | if (((int)clients.size() >= configInfoLoggerD.rxMaxConnections) && (configInfoLoggerD.rxMaxConnections > 0)) { |
502 | 565 | log.warning("Closing new client, maximum number of connections reached (%d)", configInfoLoggerD.rxMaxConnections); |
503 | 566 | close(tmpSocket); |
|
0 commit comments