diff --git a/include/crow/http_server.h b/include/crow/http_server.h index e5cff67a1..082df4298 100644 --- a/include/crow/http_server.h +++ b/include/crow/http_server.h @@ -16,8 +16,10 @@ #endif #include +#include #include #include +#include #include #include #include @@ -46,7 +48,7 @@ namespace crow // NOTE: Already documented in "crow/app.h" { public: Server(Handler* handler, - typename Acceptor::endpoint endpoint, + typename Acceptor::endpoint endpoint, std::string server_name = std::string("Crow/") + VERSION, std::tuple* middlewares = nullptr, unsigned int concurrency = 1, @@ -77,6 +79,12 @@ namespace crow // NOTE: Already documented in "crow/app.h" return; } + if(set_cloexec(acceptor_.raw_acceptor().native_handle()) == -1){ + CROW_LOG_ERROR << "Failed to set FD_CLOEXEC on start: " << std::strerror(errno); + startup_failed_ = true; + return; + } + acceptor_.raw_acceptor().set_option(Acceptor::reuse_address_option(), ec); if (ec) { CROW_LOG_ERROR << "Failed to set socket option: " << ec.message(); @@ -202,8 +210,8 @@ namespace crow // NOTE: Already documented in "crow/app.h" } handler_->port(acceptor_.port()); handler_->address_is_bound(); - CROW_LOG_INFO << server_name_ - << " server is running at " << acceptor_.url_display(handler_->ssl_used()) + CROW_LOG_INFO << server_name_ + << " server is running at " << acceptor_.url_display(handler_->ssl_used()) << " using " << concurrency_ << " threads"; CROW_LOG_INFO << "Call `app.loglevel(crow::LogLevel::Warning)` to hide Info level logs."; @@ -257,7 +265,7 @@ namespace crow // NOTE: Already documented in "crow/app.h" io_context_.stop(); // Close main io_service } - + uint16_t port() const { return acceptor_.local_endpoint().port(); } @@ -310,7 +318,7 @@ namespace crow // NOTE: Already documented in "crow/app.h" auto p = std::make_shared>( ic, handler_, server_name_, middlewares_, get_cached_date_str_pool_[context_idx], *task_timer_pool_[context_idx], adaptor_ctx_, task_queue_length_pool_[context_idx]); - + CROW_LOG_DEBUG << &ic << " {" << context_idx << "} queue length: " << task_queue_length_pool_[context_idx]; acceptor_.raw_acceptor().async_accept( @@ -318,6 +326,10 @@ namespace crow // NOTE: Already documented in "crow/app.h" [this, p, &ic](error_code ec) { if (!ec) { + if(set_cloexec(p->socket().native_handle()) == -1){ + CROW_LOG_ERROR << "Failed to set FD_CLOEXEC on accepted socket: " << std::strerror(errno); + } + asio::post(ic, [p] { p->start(); diff --git a/include/crow/socket_acceptors.h b/include/crow/socket_acceptors.h index 06afacb11..a6acce7a2 100644 --- a/include/crow/socket_acceptors.h +++ b/include/crow/socket_acceptors.h @@ -1,4 +1,7 @@ #pragma once +#ifndef _WIN32 +#include +#endif #ifdef CROW_USE_BOOST #include #ifdef CROW_ENABLE_SSL @@ -18,6 +21,24 @@ namespace crow { + /// Set FD_CLOEXEC on a native socket handle to prevent file descriptor leaking across fork/exec. + template + inline int set_cloexec([[maybe_unused]] NativeHandle fd) + { +#ifndef _WIN32 + int flags = fcntl(fd, F_GETFD); + if (flags != -1) + { + return fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + } + // Retrieving current flags failed + return flags; +#else + // Return not -1 (following fcntl()'s docs) + return 0; +#endif + } + #ifdef CROW_USE_BOOST namespace asio = boost::asio; using error_code = boost::system::error_code;