/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* Server.hpp :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: acossari +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2026/09/01 09:13:02 by acossari #+# #+# */ /* Updated: 2026/09/01 19:00:54 by acossari ### ########.fr */ /* */ /* ************************************************************************** */ #pragma once #include #include #include #include #include #include #include "event/Epoll.hpp" #include "net/Listener.hpp" #include "net/PauseMask.hpp" #include "net/SlotPool.hpp" namespace webserv { class Server final { public: // Both constants use direct-list-initialization to call the explicit // duration constructor. A bare "= 500" would need an implicit conversion // from int to std::chrono::milliseconds. // After accept() fails, listeners are temporarily disarmed before // retrying. Level-triggered epoll would otherwise keep // reporting the ready listener and create a busy loop. The 500 ms delay // matches nginx's default. static constexpr std::chrono::milliseconds ACCEPT_BACKOFF{500}; // A rare, documented race exists if SIGINT arrives after the shutdown // flag is checked but before epoll_wait begins. "epoll_pwait" closes it // atomically, but the subject does not allow it. Bounding an idle wait lets // run() recheck the flag within 500 ms. This interval is a trade-off, not a // measured optimum, and causes at most two timeout wakeups per idle second. static constexpr std::chrono::milliseconds MAX_IDLE_WAIT{500}; // TEMP // Endpoints are hardcoded in main() until the config parser is available. explicit Server(std::span endpoints); void run(); private: void dispatch(std::uint64_t packedToken, std::uint32_t events); void acceptFrom(std::uint32_t listenerIndex); void handleAcceptFailure(std::uint32_t listenerIndex, int errnoCode); void startBackoff(); void retire(std::uint32_t slotIndex) noexcept; void stopListener(std::uint32_t listenerIndex) noexcept; void updateRegistration(std::uint32_t slotIndex, std::uint32_t events); void pause(ListenerPause reason); void resume(ListenerPause reason); void applyListenerEvents(std::uint32_t events); void expireBackoff(); int millisUntilDeadline() const; Epoll epoll_; std::vector listeners_; SlotPool slotPool_; PauseMask pauseMask_; // Stores a fixed deadline because loop iterations have no fixed duration. // Empty means no resource backoff is scheduled. std::optional backoffExpiry_; }; } // namespace webserv