#ifndef LANDER_EVENT_LOOP #define LANDER_EVENT_LOOP #include #include #include // Size of the read and write buffers for each connection, in bytes #define EVENT_LOOP_BUFFER_SIZE 2048 /** * State of a connection */ typedef enum { event_loop_conn_state_req = 0, event_loop_conn_state_res = 1, event_loop_conn_state_end = 2, } event_loop_conn_state; /** * Represents an active connection managed by the event loop */ typedef struct event_loop_conn { int fd; event_loop_conn_state state; // Read buffer size_t rbuf_size; size_t rbuf_read; uint8_t rbuf[EVENT_LOOP_BUFFER_SIZE]; // Write buffer 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; // Context for a request void *ctx; } event_loop_conn; /* * Main struct object representing the event loop */ typedef struct event_loop { event_loop_conn **connections; size_t connection_count; // Global context passed to every connection void *gctx; /** * Function to initialize a connection context. * * @param gctx global context of the event loop * @return pointer to the allocated object. */ void *(*ctx_init)(void *gctx); /** * Function to free a connection context object. * * @param ctx context to free */ void (*ctx_free)(void *ctx); /** * 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. */ bool (*handle_data)(event_loop_conn *conn); /** * Function to process outgoing data while in the res state. * * @param conn connection to proces */ void (*write_data)(event_loop_conn *conn); } event_loop; /* * Initialize a new connection struct * * @param el the event loop * @return pointer to the newly allocated connection struct */ event_loop_conn *event_loop_conn_init(event_loop *el); /* * Free a connection struct * * @param el the event loop * @param conn connection struct to free */ void event_loop_conn_free(event_loop *el, event_loop_conn *conn); /* * Handle I/O for a connection, be it reading input or writing output. * * @param el the event loop * @param conn the connection to process */ void event_loop_conn_io(event_loop *el, event_loop_conn *conn); /* * Initialize a new event loop struct * * @return pointer to the newly allocated event loop struct */ event_loop *event_loop_init(); /* * Place a new connection into the event loop's internal array. * * @param el the event loop * @param conn connection to insert * @return 0 on success, -1 if the internal realloc failed. */ int event_loop_put(event_loop *el, event_loop_conn *conn); /** * Accept a new connection for the given file descriptor. * * @param el the event loop * @param fd file descriptor for the connection * @return 0 if successful, negative value otherwise */ int event_loop_accept(event_loop *el, int fd); /* * Run the event loop. This function never returns. * * @param el the event loop * @param port on what port to listen */ void event_loop_run(event_loop *el, int port); #endif