feat: perhaps kinda working event loop server?

c-web-server
Jef Roosens 2023-05-24 16:40:51 +02:00
parent 80e972ff54
commit 2ff70c02c6
Signed by: Jef Roosens
GPG Key ID: B75D4F293C7052DB
3 changed files with 32 additions and 33 deletions

View File

@ -14,20 +14,12 @@
#include "picohttpparser.h" #include "picohttpparser.h"
static int event_loop_fd_set_nb(int fd) { static int event_loop_fd_set_nb(int fd) {
int flags = fcntl(fd, F_GETFL, 0); int flags = fcntl(fd, F_GETFL);
if (errno) {
return -1;
}
flags |= O_NONBLOCK; flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags); fcntl(fd, F_SETFL, flags);
if (errno) {
return -1;
}
return 0; return 0;
} }
@ -98,8 +90,6 @@ int event_loop_accept(event_loop *loop, int fd) {
return -4; return -4;
} }
/* printf("New connection with fd %i\n", connfd); */
return 0; return 0;
} }
@ -175,23 +165,22 @@ void event_loop_run(event_loop *el, int port) {
// poll for active fds // poll for active fds
// the timeout argument doesn't matter here // the timeout argument doesn't matter here
int rv = poll(poll_args, (nfds_t)poll_args_count, 1000); int rv = poll(poll_args, (nfds_t)poll_args_count, 1000);
/* printf("poll"); */
if (rv < 0) { if (rv < 0) {
return; return;
} }
// process active connections // process active connections
for (size_t i = 1; i < poll_args_count; ++i) { for (size_t i = 1; i < poll_args_count; i++) {
if (poll_args[i].revents) { if (poll_args[i].revents) {
conn = el->connections[poll_args[i].fd]; conn = el->connections[poll_args[i].fd];
event_loop_conn_io(conn); event_loop_conn_io(conn);
if (conn->state == event_loop_conn_state_end) { if (conn->state == event_loop_conn_state_end) {
/* printf("free %i\n", conn->fd); */
// client closed normally, or something bad happened. // client closed normally, or something bad happened.
// destroy this connection // destroy this connection
el->connections[conn->fd] = NULL; el->connections[conn->fd] = NULL;
close(conn->fd); close(conn->fd);
free(conn); free(conn);
} }
@ -200,7 +189,7 @@ void event_loop_run(event_loop *el, int port) {
// try to accept a new connection if the listening fd is active // try to accept a new connection if the listening fd is active
if (poll_args[0].revents) { if (poll_args[0].revents) {
(void)event_loop_accept(el, fd); event_loop_accept(el, fd);
} }
} }
} }

View File

@ -14,7 +14,7 @@
#include "event_loop_internal.h" #include "event_loop_internal.h"
const char http_200_ok[] = "HTTP/1.1 200 OK\nConnection: close\nContent-Length: 5\n\nhello"; const char http_200_ok[] = "HTTP/1.1 200 OK\nContent-Length: 5\n\nhello";
bool event_loop_conn_io_res(event_loop_conn *conn) { bool event_loop_conn_io_res(event_loop_conn *conn) {
ssize_t res = 0; ssize_t res = 0;
@ -41,7 +41,8 @@ bool event_loop_conn_io_res(event_loop_conn *conn) {
// After writing a response, we switch back to request mode to process a next // After writing a response, we switch back to request mode to process a next
// request // request
if (conn->wbuf_sent == conn->wbuf_size) { if (conn->wbuf_sent == conn->wbuf_size) {
conn->state = conn->close_after_write ? event_loop_conn_state_end : event_loop_conn_state_req; conn->state = conn->close_after_write ? event_loop_conn_state_end
: event_loop_conn_state_req;
/* c->wbuf_sent = 0; */ /* c->wbuf_sent = 0; */
/* c->wbuf_size = 0; */ /* c->wbuf_size = 0; */
@ -53,6 +54,11 @@ bool event_loop_conn_io_res(event_loop_conn *conn) {
} }
bool try_one_request(event_loop_conn *conn) { bool try_one_request(event_loop_conn *conn) {
// We definitely can't do anything with zero bytes.
if (conn->rbuf_size == 0) {
return false;
}
/* if (conn->process_func != NULL) { */ /* if (conn->process_func != NULL) { */
/* conn->process_func(conn); */ /* conn->process_func(conn); */
/* } */ /* } */
@ -69,18 +75,19 @@ bool try_one_request(event_loop_conn *conn) {
&minor_version, headers, &num_headers, 0); &minor_version, headers, &num_headers, 0);
if (res > 0) { if (res > 0) {
/* conn->close_after_write = true; */
// TODO allow HTTP pipelining // TODO allow HTTP pipelining
conn->close_after_write = true; /* conn->close_after_write = true; */
/* for (int i = 0; i < num_headers; i++) { */ for (int i = 0; i < num_headers; i++) {
/* printf("%.*s: ", headers[i].name_len, headers[i].name); */ /* printf("%.*s: ", headers[i].name_len, headers[i].name); */
/* printf("%.*s\n", headers[i].value_len, headers[i].value); */ /* printf("%.*s\n", headers[i].value_len, headers[i].value); */
/* if (strncmp("Connection", headers[i].name, headers[i].name_len) == 0) { */ if (strncmp("Connection", headers[i].name, headers[i].name_len) == 0) {
/* if (strncmp("close", headers[i].value, headers[i].value_len) == 0) { */ if (strncmp("close", headers[i].value, headers[i].value_len) == 0) {
/* printf("close\n"); */ conn->close_after_write = true;
/* break; */ break;
/* } */ }
/* } */ }
/* } */ }
memcpy(conn->wbuf, http_200_ok, sizeof(http_200_ok) - 1); memcpy(conn->wbuf, http_200_ok, sizeof(http_200_ok) - 1);
@ -96,7 +103,8 @@ bool try_one_request(event_loop_conn *conn) {
// End the connection if the http request is invalid, or when the response // End the connection if the http request is invalid, or when the response
// is too large to fit into a single read buffer // is too large to fit into a single read buffer
} else if (res == -1 || (res == -2 && conn->rbuf_size == EVENT_LOOP_BUFFER_SIZE)) { } else if (res == -1 ||
(res == -2 && conn->rbuf_size == EVENT_LOOP_BUFFER_SIZE)) {
conn->state = event_loop_conn_state_end; conn->state = event_loop_conn_state_end;
} }
@ -135,6 +143,8 @@ bool event_loop_conn_io_req(event_loop_conn *conn) {
// change the result. // change the result.
if (res == 0) { if (res == 0) {
conn->state = event_loop_conn_state_end; conn->state = event_loop_conn_state_end;
return false;
} }
// We switch to processing mode if we've reached the end of the data stream, // We switch to processing mode if we've reached the end of the data stream,
@ -151,7 +161,8 @@ bool event_loop_conn_io_req(event_loop_conn *conn) {
// Try to process requests one by one. // Try to process requests one by one.
// Try to process requests one by one. // Try to process requests one by one.
// Why is there a loop? Please read the explanation of "pipelining". // Why is there a loop? Please read the explanation of "pipelining".
while (try_one_request(conn)) {}; while (try_one_request(conn)) {
};
// We can keep reading as long as we're in request mode // We can keep reading as long as we're in request mode
return conn->state == event_loop_conn_state_req; return conn->state == event_loop_conn_state_req;
@ -167,7 +178,6 @@ void conn_state_res(event_loop_conn *conn) {
void conn_state_req(event_loop_conn *conn) { void conn_state_req(event_loop_conn *conn) {
while (event_loop_conn_io_req(conn)) { while (event_loop_conn_io_req(conn)) {
} }
/* printf("done req"); */
} }
void event_loop_conn_io(event_loop_conn *conn) { void event_loop_conn_io(event_loop_conn *conn) {

View File

@ -1,9 +1,9 @@
#ifndef LANDER_EVENT_LOOP_INTERNAL #ifndef LANDER_EVENT_LOOP_INTERNAL
#define LANDER_EVENT_LOOP_INTERNAL #define LANDER_EVENT_LOOP_INTERNAL
#include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#include "event_loop.h" #include "event_loop.h"