diff -r 1e1fca11aaff -r 1327febf99c4 src/server/daemon/sessionhandler.c --- a/src/server/daemon/sessionhandler.c Sun Aug 11 13:26:17 2024 +0200 +++ b/src/server/daemon/sessionhandler.c Sun Aug 11 18:51:39 2024 +0200 @@ -39,11 +39,11 @@ #include "error.h" #include "httplistener.h" -typedef struct _event_http_io { +struct EventHttpIO { HTTPRequest *request; HttpParser *parser; int error; -} EventHttpIO; +}; int connection_read(Connection *conn, void *buf, int len) { @@ -222,72 +222,18 @@ } void evt_enq_conn(SessionHandler *handler, Connection *conn) { - // set socket non blocking - int flags; - if ((flags = fcntl(conn->fd, F_GETFL, 0)) == -1) { - flags = 0; - } - if (fcntl(conn->fd, F_SETFL, flags | O_NONBLOCK) != 0) { - log_ereport(LOG_FAILURE, "sessionhandler: fcntl failed: %s", strerror(errno)); + Event *event = malloc(sizeof(Event)); + if(!event) { connection_destroy(conn); return; } - HTTPRequest *request = malloc(sizeof(HTTPRequest)); - if(!request) { + EventHttpIO *io = evt_req_init(handler, conn); + if(!io) { connection_destroy(conn); - return; - } - http_request_init(request); - request->connection = conn; - conn->session_handler = handler; - - // TODO: remove code redundancy (basic_run_session) - - // read request - netbuf *buf = malloc(sizeof(netbuf)); - if(!buf) { - connection_destroy(conn); - http_request_cleanup(request); + free(event); return; } - buf->rdtimeout = 120; - buf->pos = 0; - buf->cursize = 0; - buf->maxsize = 2048; - buf->sd = &conn->fd; - buf->errmsg = NULL; - buf->inbuf = malloc(2048); - if(!buf->inbuf) { - connection_destroy(conn); - http_request_cleanup(request); - free(buf); - return; - } - - request->netbuf = buf; - - HttpParser *parser = http_parser_new(request); - if(!parser) { - connection_destroy(conn); - http_request_cleanup(request); - free(buf->inbuf); - free(buf); - return; - } - - EventHttpIO *io = malloc(sizeof(EventHttpIO)); - if(io == NULL) { - connection_destroy(conn); - http_request_cleanup(request); - free(buf->inbuf); - free(buf); - http_parser_free(parser); - return; - } - io->request = request; - io->parser = parser; - io->error = 0; /* * to start the request handling, we begin with a poll on the socket, @@ -295,7 +241,6 @@ * evt_enq_conn() --> event handler --> handle_request() */ - Event *event = malloc(sizeof(Event)); ZERO(event, sizeof(Event)); event->fn = conn->ssl && !conn->ssl_accepted ? evt_request_ssl_accept : evt_request_input; event->finish = evt_request_finish; @@ -310,6 +255,71 @@ } } +EventHttpIO* evt_req_init(SessionHandler *handler, Connection *conn) { + // set socket non blocking + int flags; + if ((flags = fcntl(conn->fd, F_GETFL, 0)) == -1) { + flags = 0; + } + if (fcntl(conn->fd, F_SETFL, flags | O_NONBLOCK) != 0) { + log_ereport(LOG_FAILURE, "sessionhandler: fcntl failed: %s", strerror(errno)); + return NULL; + } + + HTTPRequest *request = malloc(sizeof(HTTPRequest)); + if(!request) { + return NULL; + } + http_request_init(request); + request->connection = conn; + conn->session_handler = handler; + + // TODO: remove code redundancy (basic_run_session) + + // read request + netbuf *buf = malloc(sizeof(netbuf)); + if(!buf) { + http_request_cleanup(request); + return NULL; + } + buf->rdtimeout = 120; + buf->pos = 0; + buf->cursize = 0; + buf->maxsize = 2048; + buf->sd = &conn->fd; + buf->errmsg = NULL; + buf->inbuf = malloc(2048); + if(!buf->inbuf) { + http_request_cleanup(request); + free(buf); + return NULL; + } + + request->netbuf = buf; + + HttpParser *parser = http_parser_new(request); + if(!parser) { + http_request_cleanup(request); + free(buf->inbuf); + free(buf); + return NULL; + } + + EventHttpIO *io = malloc(sizeof(EventHttpIO)); + if(io == NULL) { + http_request_cleanup(request); + free(buf->inbuf); + free(buf); + http_parser_free(parser); + return NULL; + } + io->request = request; + io->parser = parser; + io->error = 0; + + return io; +} + int evt_request_ssl_accept(EventHandler *handler, Event *event) { EventHttpIO *io = event->cookie; Connection *conn = io->request->connection; @@ -481,18 +491,93 @@ } void evt_keep_alive(SessionHandler *handler, Connection *conn) { - // TODO: set timeout + Event *event = malloc(sizeof(Event)); + if(!event) { + connection_destroy(conn); + return; + } + + EVWatchList *keepalive = malloc(sizeof(EVWatchList)); + if(!keepalive) { + free(event); + connection_destroy(conn); + return; + } + + ZERO(keepalive, sizeof(EVWatchList)); + keepalive->destroy = evt_keep_alive_destroy; + keepalive->data = conn; + + ZERO(event, sizeof(Event)); + event->fn = evt_keep_alive_enqueue; + event->finish = ev_free_event; // this will free the event obj at the end + event->cookie = keepalive; + + EventHandler *ev = ev_instance(((EventSessionHandler*)handler)->eventhandler); + if(event_send(ev, event)) { + log_ereport(LOG_FAILURE, "Keep-Alive: ev_send failed"); + connection_destroy(conn); + free(event); + free(keepalive); + } +} + +int evt_keep_alive_enqueue(EventHandler *h, Event *event) { + EVWatchList *keepalive = event->cookie; + Connection *conn = keepalive->data; + + Event *ioevent = malloc(sizeof(Event)); + if(!ioevent) { + connection_destroy(conn); + free(keepalive); + return 0; + } - /* TODO: - * Don't just re-enqueue the connection - * create a evt_req_init function which does most of the evt_enq_conn stuff - * but don't poll. - * evt_keep_alive should poll and if an event occurs: - * evt_req_init - * evt_request_input - * evt_enq_conn should do: - * evt_req_init - * ev_pollin - */ - evt_enq_conn(handler, conn); + // add keepalive object to the eventhandler watchlist + // the watchlist will check the timeout + keepalive->created = time(NULL); + keepalive->expire = keepalive->created + 60; // TODO: config + ev_watchlist_add(h, keepalive); + + // wait for input + ZERO(ioevent, sizeof(Event)); + ioevent->fn = evt_keep_alive_input_event; + ioevent->finish = ev_free_event; + ioevent->cookie = keepalive; + if(ev_pollin(h, conn->fd, ioevent) != 0) { + log_ereport(LOG_FAILURE, "Cannot enqueue connection"); + ev_watchlist_remove(h, keepalive); + connection_destroy(conn); + free(keepalive); + free(ioevent); + } + + return 0; } + +int evt_keep_alive_input_event(EventHandler *h, Event *event) { + EVWatchList *keepalive = event->cookie; + Connection *conn = keepalive->data; + + // remove connection from the keep-alive list + ev_watchlist_remove(h, keepalive); + free(keepalive); + + // prepare http io + EventHttpIO *io = evt_req_init(conn->session_handler, conn); + if(!io) { + connection_destroy(conn); + return 0; + } + + // pass this event to the request input function + // the event object needs some adjustments for this (see evt_enq_conn) + event->cookie = io; + event->fn = conn->ssl && !conn->ssl_accepted ? evt_request_ssl_accept : evt_request_input; + event->finish = evt_request_finish; + return event->fn(h, event); +} + +void evt_keep_alive_destroy(EventHandler *h, EVWatchList *item) { + +}