LeftHookRoll
An HTTP/1.0 compliant web server, as specified by RFC1945
Loading...
Searching...
No Matches
ServerManager.hpp
Go to the documentation of this file.
1/**
2 * @file ServerManager.hpp
3 * @brief Owns the event loop and all listening sockets.
4 * Accepts new connections, dispatches I/O events, and routes
5 * each accepted fd to the correct ServerConf via listening-fd mapping.
6 */
7
8#pragma once
9
10#include <map>
11#include <set>
12#include <deque>
13#include <vector>
14#include <netinet/in.h>
15#include <sys/socket.h>
16#include <sys/epoll.h>
17#include "ServerConf.hpp"
18#include "Connection.hpp"
19
20#define BACKLOG 128
21#define RECV_BUFFER_SIZE 4096// keep this smaller than read buffer size in Connection.!
22#define EPOLL_TIMEOUT_MS 2500
23#define CONNECTION_TIMEOUT_S 60
24#define CGI_TIMEOUT_S 10
25
26/**
27 * @struct SockAddrCompare
28 * @brief Custom comparator for sockaddr_in to allow its use as a key in std::map.
29 */
31{
32 bool operator()(const struct sockaddr_in& lhs, const struct sockaddr_in& rhs) const
33 {
34 if (lhs.sin_addr.s_addr != rhs.sin_addr.s_addr)
35 return lhs.sin_addr.s_addr < rhs.sin_addr.s_addr;
36 return lhs.sin_port < rhs.sin_port;
37 }
38};
39
41public:
42 // Canonical Form
44 ServerManager(std::vector<ServerConf> confs);// this will be the main constructer to use once we have parsing up and ready!
45 ServerManager(const ServerManager& other);
48
49 /**
50 * @brief Creates a listening socket for the given ServerConf's IP:Port and
51 * registers the mapping.
52 * @param conf Pointer to the configuration block (pointer used to avoid heavy copying).
53 * @throws FatalException if socket setup fails.
54 */
55 void addServer(const ServerConf* conf);
56
57 /**
58 * @brief Temporary overload for early development: creates a listening socket
59 * on the given port bound to INADDR_ANY, with no ServerConf mapping.
60 */
61 void addListenPort(int port);
62
63 /**
64 * @brief Enters the main epoll() event loop. Blocks until g_running becomes false.
65 */
66 void run();
67
68 /**
69 * @brief Adds or updates an fd in the epoll list (e.g., CGI output pipe).
70 * @param fd The file descriptor to monitor.
71 * @param events EPOLLIN/EPOLLOUT mask to apply.
72 */
73 void addPollFd(int fd, uint32_t events);
74
75 /**
76 * @brief Uses getsockname() to find the local address of a client fd,
77 * then returns the matching ServerConf.
78 * @param clientFd The file descriptor returned by accept().
79 * @return const ServerConf* Pointer to the matching configuration, or NULL if not found.
80 */
81 const ServerConf* getServerConfForFd(int clientFd) const;
82
83private:
84 // conf to address mapping for quick lookup on accept():
85 std::map<struct sockaddr_in, const ServerConf*, SockAddrCompare> _interfacePortPairs;
86 std::vector<ServerConf*> _serverConfs;
87 // Round-robin processing scheduler
88 std::deque<Connection*> _processingQueue;
89 std::set<Connection*> _processingSet;
90 //connection to fd mapping on epoll events.
91 std::map<int, Connection*> _connections;
92 // CGI pipe fd -> owning Connection
93 std::map<int, Connection*> _cgiPipeToConn;
94 std::map<int, time_t> _cgiStartTimes;
95 // Event loop state
97 std::vector<struct epoll_event> _eventBuffer;
98 std::map<int, uint32_t> _fdEvents;
99 std::set<int> _listenFds;
100 std::map<int, const ServerConf*> _listenFdToServerConf;
101
102 // Private helpers
103 /**
104 * @brief Creates, binds, listens, and sets O_NONBLOCK on a socket.
105 * @return The listening fd.
106 * @throws FatalException if any socket operation fails, with the error message.
107 */
108 int _createListeningSocket(const struct sockaddr_in& addr);
109
110 /**
111 * @brief Accepts all pending connections on a listening fd.
112 * Sets each client fd to O_NONBLOCK and adds it to _pollfds.
113 */
114 void _acceptNewConnections(int listenFd);
115
116 /**
117 * @brief Reads from a client fd and prints the raw data.
118 * @return false if the client disconnected or errored, true otherwise.
119 */
120 bool _readAndPrint(int fd);
121
122 /**
123 * @brief Dispatches epoll events to the correct Connection handler
124 * and drives state transitions. Called from run() for every client event.
125 */
126 void _handleConnection(Connection* conn, uint32_t events);
127
128 /**
129 * @brief Runs a budgeted round-robin pass over _processingQueue.
130 * Calls process() once per connection, re-enqueues if still PROCESSING,
131 * budgeted to BACKLOG/2 per tick, which is arbitrary, tune as needed.
132 * @warning tribute to Prof.waleed al-maqableh.
133 */
134 void _runRoundRobin();
135
136 /**
137 * @brief Closes a client fd and removes it from epoll and _connections.
138 */
139 void _dropConnection(int fd);
140
141 /**
142 * @brief Adds a connection to the processing queue if not already queued.
143 */
144 void _enqueueProcessing(Connection* conn);
145
146 /**
147 * @brief Removes a connection from the processing set (queue cleanup is lazy).
148 */
149 void _dequeueProcessing(Connection* conn);
150
151 /**
152 * @brief Handles state transition for a connection that just left PROCESSING.
153 */
154 void _finalizeProcessed(Connection* conn);
155
156 /**
157 * @brief Scans all connections and drops any that have been idle too long.
158 */
159 void _sweepTimeouts();
160
161 /**
162 * @brief Registers a CGI pipe fd in epoll and maps it to its Connection.
163 */
164 void _registerCgiPipe(Connection* conn);
165
166 /**
167 * @brief Unregisters a CGI pipe fd from epoll and removes the mapping.
168 */
169 void _unregisterCgiPipe(int pipeFd);
170
171 /**
172 * @brief Handles an epoll event on a CGI pipe fd.
173 */
174 void _handleCgiPipeEvent(int pipeFd, uint32_t events);
175
176 /**
177 * @brief Sweeps CGI processes for timeout.
178 */
179 void _sweepCgiTimeouts();
180
181 /**
182 * need to rename this.
183 * its growing to an all encompassing cleanup function.
184 @brief Closes all fds (listeners + clients) during shutdown.
185 */
186 void _closeAllFds();
187};
Will be spawned when we accept() a new connection, will handle reading from the socket,...
Stores per-server configuration directives. This class encapsulates the configuration for a specific ...
void _enqueueProcessing(Connection *conn)
Adds a connection to the processing queue if not already queued.
void _handleCgiPipeEvent(int pipeFd, uint32_t events)
Handles an epoll event on a CGI pipe fd.
void _closeAllFds()
Closes all fds (listeners + clients) during shutdown.
std::set< int > _listenFds
void addServer(const ServerConf *conf)
Creates a listening socket for the given ServerConf's IP:Port and registers the mapping.
ServerManager & operator=(const ServerManager &other)
void _runRoundRobin()
Runs a budgeted round-robin pass over _processingQueue. Calls process() once per connection,...
const ServerConf * getServerConfForFd(int clientFd) const
Uses getsockname() to find the local address of a client fd, then returns the matching ServerConf.
void _finalizeProcessed(Connection *conn)
Handles state transition for a connection that just left PROCESSING.
void _unregisterCgiPipe(int pipeFd)
Unregisters a CGI pipe fd from epoll and removes the mapping.
std::map< struct sockaddr_in, const ServerConf *, SockAddrCompare > _interfacePortPairs
std::set< Connection * > _processingSet
void _registerCgiPipe(Connection *conn)
Registers a CGI pipe fd in epoll and maps it to its Connection.
std::deque< Connection * > _processingQueue
void addPollFd(int fd, uint32_t events)
Adds or updates an fd in the epoll list (e.g., CGI output pipe).
std::vector< ServerConf * > _serverConfs
bool _readAndPrint(int fd)
Reads from a client fd and prints the raw data.
void _handleConnection(Connection *conn, uint32_t events)
Dispatches epoll events to the correct Connection handler and drives state transitions....
void _sweepTimeouts()
Scans all connections and drops any that have been idle too long.
void addListenPort(int port)
Temporary overload for early development: creates a listening socket on the given port bound to INADD...
std::map< int, time_t > _cgiStartTimes
std::map< int, uint32_t > _fdEvents
std::map< int, const ServerConf * > _listenFdToServerConf
void _acceptNewConnections(int listenFd)
Accepts all pending connections on a listening fd. Sets each client fd to O_NONBLOCK and adds it to _...
void _dequeueProcessing(Connection *conn)
Removes a connection from the processing set (queue cleanup is lazy).
std::map< int, Connection * > _cgiPipeToConn
std::vector< struct epoll_event > _eventBuffer
int _createListeningSocket(const struct sockaddr_in &addr)
Creates, binds, listens, and sets O_NONBLOCK on a socket.
void _dropConnection(int fd)
Closes a client fd and removes it from epoll and _connections.
void run()
Enters the main epoll() event loop. Blocks until g_running becomes false.
void _sweepCgiTimeouts()
Sweeps CGI processes for timeout.
std::map< int, Connection * > _connections
Custom comparator for sockaddr_in to allow its use as a key in std::map.
bool operator()(const struct sockaddr_in &lhs, const struct sockaddr_in &rhs) const