refactore keep alive handler

Sun, 11 Aug 2024 18:51:39 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 11 Aug 2024 18:51:39 +0200
changeset 542
1327febf99c4
parent 541
1e1fca11aaff
child 543
3335f431a91b

refactore keep alive handler

src/server/daemon/event.c file | annotate | diff | comparison | revisions
src/server/daemon/event.h file | annotate | diff | comparison | revisions
src/server/daemon/event_linux.c file | annotate | diff | comparison | revisions
src/server/daemon/sessionhandler.c file | annotate | diff | comparison | revisions
src/server/daemon/sessionhandler.h file | annotate | diff | comparison | revisions
--- a/src/server/daemon/event.c	Sun Aug 11 13:26:17 2024 +0200
+++ b/src/server/daemon/event.c	Sun Aug 11 18:51:39 2024 +0200
@@ -120,6 +120,11 @@
     return ev->instances[ins];
 }
 
+int ev_free_event(EventHandler *h, Event *event) {
+    free(event);
+    return 0;
+}
+
 
 void ev_watchlist_add(EventHandler *h, EVWatchList *elm) {
     watchlist_add(&h->watchlist_begin, &h->watchlist_end, elm);
--- a/src/server/daemon/event.h	Sun Aug 11 13:26:17 2024 +0200
+++ b/src/server/daemon/event.h	Sun Aug 11 18:51:39 2024 +0200
@@ -57,13 +57,14 @@
 } EVReturn;
 
 typedef struct EVWatchList EVWatchList;
-typedef void(*evwatchlist_destroyfunc)(EventHandler *h, EVWatchList *item, void *data);
+typedef void(*evwatchlist_destroyfunc)(EventHandler *h, EVWatchList *item);
 
 struct EVWatchList {
     time_t created;
     time_t expire;
     evwatchlist_destroyfunc destroy;
-    void *destroydata;
+    void *data;
+    int intdata;
     EVWatchList *prev;
     EVWatchList *next;
 };
@@ -111,6 +112,8 @@
 int ev_aioread(int fd, aiocb_s *cb);
 int ev_aiowrite(int fd, aiocb_s *cb);
 
+int ev_free_event(EventHandler *h, Event *event);
+
 void ev_saf_return(EventHandler *h, Session *sn, Request *rq, int ret);
 
 void ev_watchlist_add(EventHandler *h, EVWatchList *elm);
--- a/src/server/daemon/event_linux.c	Sun Aug 11 13:26:17 2024 +0200
+++ b/src/server/daemon/event_linux.c	Sun Aug 11 18:51:39 2024 +0200
@@ -135,7 +135,7 @@
                 int saved_ev = event->events;
                 if(!event->fn(h, event)) {
                     // event fn returned 0 -> remove event from epoll
-                    if(epoll_ctl(ep, EPOLL_CTL_DEL, event->object, NULL)) {
+                    if(saved_ev && epoll_ctl(ep, EPOLL_CTL_DEL, event->object, NULL)) {
                         event->error = 1;
                         log_ereport(
                                 LOG_FAILURE,
--- 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) {
+    
+}
--- a/src/server/daemon/sessionhandler.h	Sun Aug 11 13:26:17 2024 +0200
+++ b/src/server/daemon/sessionhandler.h	Sun Aug 11 18:51:39 2024 +0200
@@ -123,6 +123,7 @@
  * 
  * defined in sesionhandler.c
  */
+typedef struct EventHttpIO EventHttpIO;
 
 int connection_read(Connection *conn, void *buf, int len);
 int connection_write(Connection *conn, const void *buf, int len);
@@ -157,6 +158,8 @@
 
 void evt_enq_conn(SessionHandler *handler, Connection *conn);
 
+EventHttpIO* evt_req_init(SessionHandler *handler, Connection *conn);
+
 int evt_request_ssl_accept(EventHandler *handler, Event *event);
 int evt_request_input(EventHandler *h, Event *event);
 int evt_request_finish(EventHandler *h, Event *event);
@@ -164,6 +167,10 @@
 
 void evt_keep_alive(SessionHandler *handler, Connection *conn);
 
+int evt_keep_alive_enqueue(EventHandler *h, Event *event);
+int evt_keep_alive_input_event(EventHandler *h, Event *event);
+
+void evt_keep_alive_destroy(EventHandler *h, EVWatchList *item);
 
 #ifdef	__cplusplus
 }

mercurial