1515#include <sys/types.h>
1616#include <sys/stat.h>
1717#include <sys/epoll.h>
18+ #include <sys/timerfd.h>
1819#include <netinet/in.h>
1920#include <arpa/inet.h>
2021
@@ -66,6 +67,13 @@ void signal_handler(int signal_number)
6667 */
6768int main ()
6869{
70+ // We are going to use epoll to handle events on the server socket and all
71+ // incoming client sockets.
72+ struct epoll_event ev , events [MAX_EVENTS ];
73+ // Not required but just prevents valgrind warning :).
74+ memset (& ev .data , '\0' , sizeof (epoll_data_t ));
75+ int epollfd , num_fds ;
76+
6977 // Create a socket, using ipv4 and tcp.
7078 int yes = 1 ;
7179 int server_socket = socket (AF_INET , SOCK_STREAM , 0 );
@@ -82,10 +90,14 @@ int main()
8290 // Show the address we are listening on.
8391 show_server_address (& address );
8492
85- /**
86- * Register signal handler, we can do this now since we are prepared
87- * to exit gracefully.
88- */
93+ // Initialize the epoll struct and register the server socket.
94+ epollfd = epoll_create1 (0 );
95+ ev .events = EPOLLIN ;
96+ ev .data .fd = server_socket ;
97+ epoll_ctl (epollfd , EPOLL_CTL_ADD , server_socket , & ev );
98+
99+ // Register signal handler, we can do this now since we are prepared
100+ // to exit gracefully.
89101 struct sigaction sig_int ;
90102 memset (& sig_int , 0 , sizeof (sig_int ));
91103 sig_int .sa_handler = signal_handler ;
@@ -96,76 +108,107 @@ int main()
96108
97109 while (running )
98110 {
99- // Accept any incoming connections.
100- struct sockaddr_in client_address ;
101- socklen_t sock_size = sizeof (struct sockaddr_in );
102- client_socket = accept (server_socket ,
103- (struct sockaddr * )& client_address , & sock_size );
104-
105- printf ("------ Connection established ------\n" );
106-
107- // Read incoming connection's ip address.
108- display_peer_ip ((struct sockaddr * )& client_address .sin_addr );
109-
110- // We need to keep reading from this socket until we encounter an
111- // error, timeout or "Connection: close"
112- bool connection = true;
113- while (connection )
111+ // Wait for an incoming connection on the server socket.
112+ num_fds = epoll_wait (epollfd , events , MAX_EVENTS , -1 );
113+ // Encountered error waiting for event.
114+ if (num_fds == -1 )
115+ perror ("epoll_wait" );
116+
117+ // Iterate over the returned number of fds
118+ for (int n = 0 ; n < num_fds ; n ++ )
114119 {
115- // Read and validate data if any is avaliable.
116- HTTP_REQUEST request = {
117- .version = UNSUPPORTED ,
118- .method = INV_METHOD ,
119- .path = NULL ,
120- .headers = NULL ,
121- .header_number = 0 ,
122- .body = NULL ,
123- };
124-
125- READ_STATES read_state = read_single_http_message (client_socket ,
126- & request );
127- switch (read_state )
120+ // Are we handling events from the server socket? (Connections?)
121+ if (events [n ].data .fd == server_socket )
128122 {
129- case INVALID_DATA_READ :
130- case MANUALLY_INTERRUPTED_READ :
131- case UNEXPECTED_CLOSED_READ :
132- printf ("Error encountered reading packet: %s\n" ,
133- READ_STATES_STRING [read_state ]);
134- connection = false;
135- if (request .path != NULL )
136- free (request .path );
137- continue ;
138- case FINISHED_READ :
139- // Show the breakdown of the http request.
140- show_http_request (& request );
141- // Filter data and action if required.
142- HTTP_RESPONSE res ;
143- filter_request (client_socket , request , & res );
144- break ;
145- case NO_DATA_READ :
146- connection = false;
147- break ;
148- default :
149- break ;
123+ struct sockaddr_in client_address ;
124+ socklen_t sock_size = sizeof (struct sockaddr_in );
125+ client_socket = accept (server_socket ,
126+ (struct sockaddr * )& client_address ,
127+ & sock_size );
128+ if (client_socket == -1 )
129+ {
130+ perror ("Error accepting the connection." );
131+ running = false;
132+ continue ;
133+ }
134+
135+ // Set socket as non blocking.
136+ fcntl (client_socket , F_SETFL ,
137+ fcntl (client_socket , F_GETFL ) | O_NONBLOCK );
138+
139+ // Add socket to epoll.
140+ ev .events = EPOLLIN | EPOLLET ;
141+ ev .data .fd = client_socket ;
142+ if (epoll_ctl (epollfd , EPOLL_CTL_ADD , client_socket ,
143+ & ev ) == -1 )
144+ {
145+ perror ("epoll_ctl: client_socket" );
146+ }
147+
148+ printf ("------ Connection established ------\n" );
149+
150+ // Read incoming connection's ip address.
151+ display_peer_ip ((struct sockaddr * )& client_address .sin_addr );
150152 }
151-
152- // Are we keep-alive?
153- const char * keep_alive = get_http_header_value (request ,
154- "Connection" );
155- if (keep_alive == NULL || strcmp (keep_alive , "keep-alive" ) != 0 )
153+ else
156154 {
157- connection = false;
155+ // Only other sockets are clients.
156+ // Are we reading or disconnecting?
157+ int connection = true;
158+
159+ // Read and validate data if any is avaliable.
160+ HTTP_REQUEST request = {
161+ .version = UNSUPPORTED ,
162+ .method = INV_METHOD ,
163+ .path = NULL ,
164+ .headers = NULL ,
165+ .header_number = 0 ,
166+ .body = NULL ,
167+ };
168+
169+ READ_STATES read_state = read_single_http_message (client_socket ,
170+ & request );
171+ switch (read_state )
172+ {
173+ case INVALID_DATA_READ :
174+ case MANUALLY_INTERRUPTED_READ :
175+ case UNEXPECTED_CLOSED_READ :
176+ case NO_DATA_READ :
177+ printf ("Error encountered reading packet: %s\n" ,
178+ READ_STATES_STRING [read_state ]);
179+ connection = false;
180+ if (request .path != NULL )
181+ free (request .path );
182+ break ;
183+ case FINISHED_READ :
184+ // Show the breakdown of the http request.
185+ show_http_request (& request );
186+ // Filter data and action if required.
187+ HTTP_RESPONSE res ;
188+ filter_request (client_socket , request , & res );
189+ // Are we keep-alive?
190+ const char * keep_alive = get_http_header_value (request ,
191+ "Connection" );
192+ if (keep_alive == NULL || strcmp (keep_alive , "keep-alive" ) != 0 )
193+ {
194+ connection = false;
195+ }
196+ break ;
197+ default :
198+ break ;
199+ }
200+
201+ if (connection == false)
202+ {
203+ close (client_socket );
204+ client_socket = -1 ;
205+ printf ("--------- Connection closed --------\n" );
206+ }
207+
208+ // Free data.
209+ free_http_request (& request );
158210 }
159-
160- // Free data.
161- free_http_request (& request );
162211 }
163-
164- // Close the connection.
165- close (client_socket );
166- client_socket = -1 ;
167-
168- printf ("--------- Connection closed --------\n" );
169212 }
170213
171214 printf ("Exiting now...\n" );
@@ -179,21 +222,7 @@ int main()
179222 */
180223READ_STATES read_single_http_message (int s , HTTP_REQUEST * req )
181224{
182- // Use select to prevent recv from blocking until there is
183- // something to read.
184- sigset_t mask ;
185- sigset_t other_mask ;
186- sigemptyset (& mask );
187- sigaddset (& mask , SIGINT );
188- sigprocmask (1 , & mask , & other_mask );
189- fd_set fds ;
190- FD_ZERO (& fds );
191- FD_SET (s , & fds );
192- struct timespec timeout = {.tv_nsec = 3000 };
193- pselect (s + 1 , & fds , NULL , NULL , & timeout , NULL );
194- fcntl (s , F_SETFL , fcntl (s , F_GETFL ) | O_NONBLOCK );
195-
196- // Actually read from the socket into the temporary buffer.
225+ // Read from the socket into the temporary buffer.
197226 char temp_buff [DEFAULT_PAYLOAD_SIZE ];
198227 ssize_t bytes_read = 0 ;
199228
0 commit comments