2023-05-24 12:05:09 +02:00
|
|
|
#ifndef LANDER_EVENT_LOOP
|
|
|
|
#define LANDER_EVENT_LOOP
|
|
|
|
|
2023-05-25 22:58:00 +02:00
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2023-05-24 12:05:09 +02:00
|
|
|
// Size of the read and write buffers for each connection, in bytes
|
|
|
|
#define EVENT_LOOP_BUFFER_SIZE 1024
|
|
|
|
|
|
|
|
/**
|
2023-05-27 15:38:06 +02:00
|
|
|
* State of a connection
|
2023-05-24 12:05:09 +02:00
|
|
|
*/
|
|
|
|
typedef enum {
|
|
|
|
event_loop_conn_state_req = 0,
|
|
|
|
event_loop_conn_state_res = 1,
|
|
|
|
event_loop_conn_state_end = 2,
|
|
|
|
} event_loop_conn_state;
|
|
|
|
|
2023-05-27 15:38:06 +02:00
|
|
|
/**
|
|
|
|
* Represents an active connection managed by the event loop
|
|
|
|
*/
|
2023-05-25 22:58:00 +02:00
|
|
|
typedef struct event_loop_conn {
|
|
|
|
int fd;
|
|
|
|
event_loop_conn_state state;
|
2023-05-27 15:38:06 +02:00
|
|
|
// Read buffer
|
2023-05-25 22:58:00 +02:00
|
|
|
size_t rbuf_size;
|
|
|
|
size_t rbuf_read;
|
|
|
|
uint8_t rbuf[EVENT_LOOP_BUFFER_SIZE];
|
2023-05-27 15:38:06 +02:00
|
|
|
// Write buffer
|
2023-05-25 22:58:00 +02:00
|
|
|
size_t wbuf_size;
|
|
|
|
size_t wbuf_sent;
|
|
|
|
uint8_t wbuf[EVENT_LOOP_BUFFER_SIZE];
|
|
|
|
|
|
|
|
// If true, the server will close the connection after the final write buffer
|
|
|
|
// has been written
|
|
|
|
bool close_after_write;
|
2023-05-27 15:38:06 +02:00
|
|
|
// Context for a request
|
2023-05-27 11:47:39 +02:00
|
|
|
void *ctx;
|
2023-05-25 22:58:00 +02:00
|
|
|
} event_loop_conn;
|
|
|
|
|
|
|
|
/*
|
2023-05-27 11:47:39 +02:00
|
|
|
* Main struct object representing the event loop
|
2023-05-25 22:58:00 +02:00
|
|
|
*/
|
2023-05-27 11:47:39 +02:00
|
|
|
typedef struct event_loop {
|
|
|
|
event_loop_conn **connections;
|
|
|
|
size_t connection_count;
|
|
|
|
// Global context passed to every connection
|
|
|
|
void *gctx;
|
2023-05-31 16:49:15 +02:00
|
|
|
/**
|
|
|
|
* Function to initialize a connection context.
|
|
|
|
*
|
|
|
|
* @param gctx global context of the event loop
|
|
|
|
* @return pointer to the allocated object.
|
|
|
|
*/
|
2023-05-27 11:47:39 +02:00
|
|
|
void *(*ctx_init)(void *gctx);
|
2023-05-31 16:49:15 +02:00
|
|
|
/**
|
|
|
|
* Function to free a connection context object.
|
|
|
|
*
|
|
|
|
* @param ctx context to free
|
|
|
|
*/
|
2023-05-27 11:47:39 +02:00
|
|
|
void (*ctx_free)(void *ctx);
|
2023-05-31 16:49:15 +02:00
|
|
|
/**
|
|
|
|
* Function to process incoming data while in the req state.
|
|
|
|
*
|
|
|
|
* @param conn connection to process
|
|
|
|
* @return whether the function can be called again immediately in the same
|
|
|
|
* event loop cycle. This allows quicly processing multiple requests without
|
|
|
|
* waiting for I/O.
|
|
|
|
*/
|
2023-05-27 11:47:39 +02:00
|
|
|
bool (*handle_data)(event_loop_conn *conn);
|
2023-05-31 16:49:15 +02:00
|
|
|
/**
|
|
|
|
* Function to process outgoing data while in the res state.
|
|
|
|
*
|
|
|
|
* @param conn connection to proces
|
|
|
|
*/
|
2023-05-29 11:36:57 +02:00
|
|
|
void (*write_data)(event_loop_conn *conn);
|
2023-05-27 11:47:39 +02:00
|
|
|
} event_loop;
|
2023-05-26 22:12:53 +02:00
|
|
|
|
|
|
|
/*
|
2023-05-27 15:38:06 +02:00
|
|
|
* Initialize a new connection struct
|
2023-05-31 16:49:15 +02:00
|
|
|
*
|
|
|
|
* @param el the event loop
|
|
|
|
* @return pointer to the newly allocated connection struct
|
2023-05-26 22:12:53 +02:00
|
|
|
*/
|
2023-05-27 11:47:39 +02:00
|
|
|
event_loop_conn *event_loop_conn_init(event_loop *el);
|
|
|
|
|
2023-05-27 15:38:06 +02:00
|
|
|
/*
|
|
|
|
* Free a connection struct
|
2023-05-31 16:49:15 +02:00
|
|
|
*
|
|
|
|
* @param el the event loop
|
|
|
|
* @param conn connection struct to free
|
2023-05-27 15:38:06 +02:00
|
|
|
*/
|
2023-05-27 11:47:39 +02:00
|
|
|
void event_loop_conn_free(event_loop *el, event_loop_conn *conn);
|
2023-05-25 22:58:00 +02:00
|
|
|
|
2023-05-26 22:12:53 +02:00
|
|
|
/*
|
2023-05-27 15:38:06 +02:00
|
|
|
* Handle I/O for a connection, be it reading input or writing output.
|
2023-05-31 16:49:15 +02:00
|
|
|
*
|
|
|
|
* @param el the event loop
|
|
|
|
* @param conn the connection to process
|
2023-05-26 22:12:53 +02:00
|
|
|
*/
|
2023-05-27 11:47:39 +02:00
|
|
|
void event_loop_conn_io(event_loop *el, event_loop_conn *conn);
|
2023-05-25 22:58:00 +02:00
|
|
|
|
|
|
|
/*
|
2023-05-27 15:38:06 +02:00
|
|
|
* Initialize a new event loop struct
|
2023-05-31 16:49:15 +02:00
|
|
|
*
|
|
|
|
* @return pointer to the newly allocated event loop struct
|
2023-05-25 22:58:00 +02:00
|
|
|
*/
|
2023-05-27 11:47:39 +02:00
|
|
|
event_loop *event_loop_init();
|
2023-05-25 22:58:00 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Place a new connection into the event loop's internal array.
|
|
|
|
*
|
2023-05-31 16:49:15 +02:00
|
|
|
* @param el the event loop
|
|
|
|
* @param conn connection to insert
|
|
|
|
* @return 0 on success, -1 if the internal realloc failed.
|
2023-05-25 22:58:00 +02:00
|
|
|
*/
|
2023-05-27 11:47:39 +02:00
|
|
|
int event_loop_put(event_loop *el, event_loop_conn *conn);
|
2023-05-25 22:58:00 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Accept a new connection for the given file descriptor.
|
2023-05-31 16:49:15 +02:00
|
|
|
*
|
|
|
|
* @param el the event loop
|
|
|
|
* @param fd file descriptor for the connection
|
|
|
|
* @return 0 if successful, negative value otherwise
|
2023-05-25 22:58:00 +02:00
|
|
|
*/
|
2023-05-27 11:47:39 +02:00
|
|
|
int event_loop_accept(event_loop *el, int fd);
|
2023-05-25 22:58:00 +02:00
|
|
|
|
2023-05-26 22:12:53 +02:00
|
|
|
/*
|
|
|
|
* Run the event loop. This function never returns.
|
2023-05-31 16:49:15 +02:00
|
|
|
*
|
|
|
|
* @param el the event loop
|
|
|
|
* @param port on what port to listen
|
2023-05-26 22:12:53 +02:00
|
|
|
*/
|
|
|
|
void event_loop_run(event_loop *el, int port);
|
2023-05-25 22:58:00 +02:00
|
|
|
|
2023-05-24 12:05:09 +02:00
|
|
|
#endif
|