From ad7443000634e77da5cfcd92e9507f954ad2b85d Mon Sep 17 00:00:00 2001 From: Shaohan Date: Tue, 11 Aug 2026 11:18:16 +0200 Subject: [PATCH 1/3] #1188 fix: Add max connections to prevent fds from hitting the limit --- include/crow/app.h | 12 ++++++++++-- include/crow/http_server.h | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/crow/app.h b/include/crow/app.h index 7aa60522d..533bea034 100644 --- a/include/crow/app.h +++ b/include/crow/app.h @@ -464,6 +464,13 @@ namespace crow return concurrency_; } + /// \brief Set the maximum number of concurrent connections (default is unlimited with value std::nullopt) + self_t& max_connections(size_t size) + { + max_connections_ = size; + return *this; + } + /// \brief Set the server's log level /// /// Possible values are: @@ -655,7 +662,7 @@ namespace crow if (use_unix_) { UnixSocketAcceptor::endpoint endpoint(bindaddr_); - unix_server_ = std::move(std::unique_ptr(new unix_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr))); + unix_server_ = std::move(std::unique_ptr(new unix_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, max_connections_, timeout_, nullptr))); unix_server_->set_tick_function(tick_interval_, tick_function_); for (auto snum : signals_) { @@ -673,7 +680,7 @@ namespace crow return; } TCPAcceptor::endpoint endpoint(addr, port_); - server_ = std::move(std::unique_ptr(new server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, nullptr, tcp_socket_options_))); + server_ = std::move(std::unique_ptr(new server_t(this, endpoint, server_name_, &middlewares_, concurrency_, max_connections_, timeout_, nullptr, tcp_socket_options_))); server_->set_tick_function(tick_interval_, tick_function_); for (auto snum : signals_) { @@ -912,6 +919,7 @@ namespace crow std::uint8_t timeout_{5}; uint16_t port_ = 80; unsigned int concurrency_ = 2; + std::optional max_connections_; std::atomic_bool is_bound_ = false; uint64_t max_payload_{UINT64_MAX}; std::string server_name_ = std::string("Crow/") + VERSION; diff --git a/include/crow/http_server.h b/include/crow/http_server.h index c04e4f158..652107cca 100644 --- a/include/crow/http_server.h +++ b/include/crow/http_server.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "crow/version.h" #include "crow/http_connection.h" @@ -51,11 +52,13 @@ namespace crow // NOTE: Already documented in "crow/app.h" std::string server_name = std::string("Crow/") + VERSION, std::tuple* middlewares = nullptr, unsigned int concurrency = 1, + std::optional max_connections = std::nullopt, uint8_t timeout = 5, typename Adaptor::context* adaptor_ctx = nullptr, detail::socket::tcp_socket_options tcp_socket_options = {}): concurrency_(concurrency), task_queue_length_pool_(concurrency_ - 1), + max_task_queue_length_(max_connections), acceptor_(io_context_), signals_(io_context_), tick_timer_(io_context_), @@ -318,8 +321,12 @@ namespace crow // NOTE: Already documented in "crow/app.h" acceptor_.raw_acceptor().async_accept( p->socket(), - [this, p, &ic](error_code ec) { - if (!ec) + [this, p, &ic, context_idx](error_code ec) { + if(max_task_queue_length_.has_value() && task_queue_length_pool_[context_idx] > max_task_queue_length_.value()) + { + CROW_LOG_DEBUG << "Too many queued tasks for io context " << &ic << " {" << context_idx << "}, rejecting connection. Queue length: " << task_queue_length_pool_[context_idx]; + } + else if (!ec) { detail::socket::apply_tcp_socket_options(p->socket(), tcp_socket_options_); asio::post(ic, @@ -343,6 +350,7 @@ namespace crow // NOTE: Already documented in "crow/app.h" private: unsigned int concurrency_{2}; std::vector> task_queue_length_pool_; + std::optional max_task_queue_length_; std::vector> io_context_pool_; asio::io_context io_context_; std::vector task_timer_pool_; From 8d9745cadcd77f042260f5f83032cae69265fa6c Mon Sep 17 00:00:00 2001 From: Shaohan Date: Wed, 12 Aug 2026 10:28:32 +0200 Subject: [PATCH 2/3] Use size_t with default 0 for max connections --- include/crow/app.h | 4 ++-- include/crow/http_server.h | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/crow/app.h b/include/crow/app.h index 533bea034..095545bb7 100644 --- a/include/crow/app.h +++ b/include/crow/app.h @@ -464,7 +464,7 @@ namespace crow return concurrency_; } - /// \brief Set the maximum number of concurrent connections (default is unlimited with value std::nullopt) + /// \brief Set the maximum number of concurrent connections (default is unlimited with value 0) self_t& max_connections(size_t size) { max_connections_ = size; @@ -919,7 +919,7 @@ namespace crow std::uint8_t timeout_{5}; uint16_t port_ = 80; unsigned int concurrency_ = 2; - std::optional max_connections_; + size_t max_connections_{}; std::atomic_bool is_bound_ = false; uint64_t max_payload_{UINT64_MAX}; std::string server_name_ = std::string("Crow/") + VERSION; diff --git a/include/crow/http_server.h b/include/crow/http_server.h index 652107cca..4a80de0c6 100644 --- a/include/crow/http_server.h +++ b/include/crow/http_server.h @@ -52,7 +52,7 @@ namespace crow // NOTE: Already documented in "crow/app.h" std::string server_name = std::string("Crow/") + VERSION, std::tuple* middlewares = nullptr, unsigned int concurrency = 1, - std::optional max_connections = std::nullopt, + size_t max_connections = 0, uint8_t timeout = 5, typename Adaptor::context* adaptor_ctx = nullptr, detail::socket::tcp_socket_options tcp_socket_options = {}): @@ -322,7 +322,7 @@ namespace crow // NOTE: Already documented in "crow/app.h" acceptor_.raw_acceptor().async_accept( p->socket(), [this, p, &ic, context_idx](error_code ec) { - if(max_task_queue_length_.has_value() && task_queue_length_pool_[context_idx] > max_task_queue_length_.value()) + if(max_task_queue_length_ > 0 && task_queue_length_pool_[context_idx] > max_task_queue_length_) { CROW_LOG_DEBUG << "Too many queued tasks for io context " << &ic << " {" << context_idx << "}, rejecting connection. Queue length: " << task_queue_length_pool_[context_idx]; } @@ -350,7 +350,7 @@ namespace crow // NOTE: Already documented in "crow/app.h" private: unsigned int concurrency_{2}; std::vector> task_queue_length_pool_; - std::optional max_task_queue_length_; + size_t max_task_queue_length_{}; std::vector> io_context_pool_; asio::io_context io_context_; std::vector task_timer_pool_; From 395667d8381b21670c175b68a0c2aece25e21b0b Mon Sep 17 00:00:00 2001 From: gittiver Date: Thu, 13 Aug 2026 14:19:57 +0200 Subject: [PATCH 3/3] Update ssl_server initialization with max_connections --- include/crow/app.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/crow/app.h b/include/crow/app.h index 095545bb7..adbcc3225 100644 --- a/include/crow/app.h +++ b/include/crow/app.h @@ -646,7 +646,7 @@ namespace crow } tcp::endpoint endpoint(addr, port_); router_.using_ssl = true; - ssl_server_ = std::move(std::unique_ptr(new ssl_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, timeout_, &ssl_context_, tcp_socket_options_))); + ssl_server_ = std::move(std::unique_ptr(new ssl_server_t(this, endpoint, server_name_, &middlewares_, concurrency_, max_connections_, timeout_, &ssl_context_, tcp_socket_options_))); ssl_server_->set_tick_function(tick_interval_, tick_function_); ssl_server_->signal_clear(); for (auto snum : signals_)