#pragma once #include "config.hpp" #include "connection_handler.hpp" #include #include #include #include /** * High-performance multi-threaded server for handling network connections. * * The Server class encapsulates all networking logic including: * - Socket management and configuration * - Multi-threaded epoll-based I/O multiplexing * - Connection lifecycle management * - Graceful shutdown handling * * The server uses a configurable thread pool architecture: * - Accept threads: Handle incoming connections with load balancing * - Network threads: Process I/O events for established connections * * All protocol-specific logic is delegated to the provided ConnectionHandler, * maintaining clean separation between networking and application logic. * * IMPORTANT: Server uses a factory pattern and MUST be created via * Server::create(). This ensures: * - Proper shared_ptr semantics for enable_shared_from_this * - Safe weak_ptr references from Connection objects * - Prevention of accidental stack allocation that would break safety * guarantees */ class Server : public std::enable_shared_from_this { public: /** * Factory method to create a Server instance. * * This is the only way to create a Server - ensures proper shared_ptr * semantics and prevents accidental stack allocation that would break * weak_ptr safety. * * @param config Server configuration (threads, ports, limits, etc.) * @param handler Protocol handler for processing connection data * @return shared_ptr to the newly created Server */ static std::shared_ptr create(const weaseldb::Config &config, ConnectionHandler &handler); /** * Destructor ensures proper cleanup of all resources. */ ~Server(); /** * Start the server and begin accepting connections. * * This method: * - Creates and configures the listen socket * - Starts all worker threads * - Blocks until shutdown() is called or an error occurs * * @throws std::runtime_error on socket creation or configuration errors */ void run(); /** * Initiate graceful server shutdown. * * This method is async-signal-safe and can be called from signal handlers. * It signals all threads to stop processing and begin cleanup. * * The run() method will return after all threads have completed shutdown. */ void shutdown(); /** * Release a connection back to its server for continued processing. * * This static method safely returns ownership of a connection back to its * server. If the server has been destroyed, the connection will be safely * cleaned up. * * This method is thread-safe and can be called from any thread. * * @param connection unique_ptr to the connection being released back */ static void releaseBackToServer(std::unique_ptr connection); private: /** * Private constructor - use create() factory method instead. * * @param config Server configuration (threads, ports, limits, etc.) * @param handler Protocol handler for processing connection data */ explicit Server(const weaseldb::Config &config, ConnectionHandler &handler); const weaseldb::Config &config_; ConnectionHandler &handler_; // Thread management std::vector threads_; std::atomic connection_id_{0}; // Shutdown coordination int shutdown_pipe_[2] = {-1, -1}; // Epoll file descriptors int network_epollfd_ = -1; int accept_epollfd_ = -1; int listen_sockfd_ = -1; // Private helper methods void setup_shutdown_pipe(); void setup_signal_handling(); int create_listen_socket(); void start_network_threads(); void start_accept_threads(); void cleanup_resources(); // Helper for processing connection I/O (shared between accept and network // threads) bool process_connection_io(std::unique_ptr &conn, int events); /** * Called internally to return ownership to the server. * * This method is thread-safe and can be called from any thread. * The connection will be re-added to the epoll for continued processing. * * @param connection Raw pointer to the connection being released back */ void receiveConnectionBack(Connection *connection); // Make non-copyable and non-movable Server(const Server &) = delete; Server &operator=(const Server &) = delete; Server(Server &&) = delete; Server &operator=(Server &&) = delete; };