From 449fabba51db156af4ca11929b91b80b5a201e85 Mon Sep 17 00:00:00 2001 From: yrutschle Date: Sun, 24 Apr 2022 18:35:09 +0200 Subject: [PATCH] linked list sorted by timeout times --- common.h | 9 +++++++ sslh-conf.c | 2 +- sslh-conf.h | 3 ++- sslh-main.c | 3 +++ sslhconf.cfg | 3 ++- udp-listener.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 82 insertions(+), 4 deletions(-) diff --git a/common.h b/common.h index 9732692..6f6e76c 100644 --- a/common.h +++ b/common.h @@ -92,6 +92,12 @@ struct queue { int deferred_data_size; }; +/* Double linked list for timeout management */ +typedef struct { + struct connection* head; + struct connection* tail; +} dl_list; + struct connection { int type; /* SOCK_DGRAM | SOCK_STREAM */ struct sslhcfg_protocols_item* proto; /* Where to connect to */ @@ -113,6 +119,9 @@ struct connection { time_t last_active; + /* double linked list of timeouts */ + struct connection *timeout_prev, *timeout_next; + /* We need one local socket for each target server, so we know where to * forward server responses */ int target_sock; diff --git a/sslh-conf.c b/sslh-conf.c index c196f5a..936ff01 100644 --- a/sslh-conf.c +++ b/sslh-conf.c @@ -1,5 +1,5 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) - * on Sun Apr 10 08:52:30 2022. + * on Mon Apr 18 21:21:32 2022. # conf2struct: generate libconf parsers that read to structs # Copyright (C) 2018-2021 Yves Rutschle diff --git a/sslh-conf.h b/sslh-conf.h index 6a51b38..bf6e68d 100644 --- a/sslh-conf.h +++ b/sslh-conf.h @@ -1,5 +1,5 @@ /* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README) - * on Sun Apr 10 08:52:30 2022. + * on Mon Apr 18 21:21:32 2022. # conf2struct: generate libconf parsers that read to structs # Copyright (C) 2018-2021 Yves Rutschle @@ -72,6 +72,7 @@ struct sslhcfg_protocols_item { T_PROBE* probe; struct addrinfo* saddr; void* data; + dl_list timeouts; }; struct sslhcfg_item { diff --git a/sslh-main.c b/sslh-main.c index 48d1824..8da044b 100644 --- a/sslh-main.c +++ b/sslh-main.c @@ -160,6 +160,9 @@ static void config_protocols() (const char**) cfg.protocols[i].alpn_protocols, cfg.protocols[i].alpn_protocols_len); } + + p->timeouts.head = NULL; + p->timeouts.tail = NULL; } } diff --git a/sslhconf.cfg b/sslhconf.cfg index 9667e29..dde2844 100644 --- a/sslhconf.cfg +++ b/sslhconf.cfg @@ -133,7 +133,8 @@ config: { # Runtime data { name: "probe"; type: "runtime"; c_type: "T_PROBE*" }, { name: "saddr"; type: "runtime"; c_type: "struct addrinfo*" }, - { name: "data"; type: "runtime"; c_type: "void*" } + { name: "data"; type: "runtime"; c_type: "void*" }, + { name: "timeouts"; type: "runtime"; c_type: "dl_list" } ) } ) diff --git a/udp-listener.c b/udp-listener.c index 06966be..3efcdcb 100644 --- a/udp-listener.c +++ b/udp-listener.c @@ -117,6 +117,61 @@ static int new_source(hash* h, struct connection* new) } +/* Double linked list utilities: push element at tail of list */ +static void list_push(dl_list* list, struct connection* cnx) +{ + cnx->timeout_next = NULL; + + if (!list->head) { + cnx->timeout_prev = NULL; + list->head = cnx; + } + + if (list->tail) { + list->tail->timeout_next = cnx; + cnx->timeout_prev = list->tail; + } + + list->tail = cnx; +} + +/* Double linked list utilities: remove element */ +static void list_remove(dl_list* list, struct connection* cnx) +{ + if (list->head == cnx) list->head = cnx->timeout_next; + if (list->tail == cnx) list->tail = cnx->timeout_prev; + + if (cnx->timeout_prev) + cnx->timeout_prev->timeout_next = cnx->timeout_next; + + if (cnx->timeout_next) + cnx->timeout_next->timeout_prev = cnx->timeout_prev; +} + +static void list_dump(void) { + int now = time(NULL); + static int cnt = 0; + + if (cnt++ < 1000) { + return; + } + cnt = 0; + + FILE * f = fopen("/tmp/list.tmp", "w"); + fprintf(f, "time: %d\n", time(NULL)); + for (int i = 0; i < cfg.protocols_len; i++) { + struct connection* c = cfg.protocols[i].timeouts.head; + fprintf(f, "p %d %s list %p %p\n", i, cfg.protocols[i].name, cfg.protocols[i].timeouts.head, cfg.protocols[i].timeouts.tail); + while (c) { + fprintf(f, "%p %d(%d) %p %p\n", c, c->last_active, now - c->last_active, c->timeout_prev, c->timeout_next); + c = c->timeout_next; + } + fprintf(f, "/list\n"); + } + fclose(f); + rename("/tmp/list.tmp", "/tmp/list"); +} + /* Check all connections to see if a UDP connections has timed out, then free * it. At the same time, keep track of the closest, next timeout. Only do the @@ -152,8 +207,9 @@ void udp_timeouts(struct loop_info* fd_info) close(cnx->target_sock); watchers_del_read(fd_info->watchers, i); watchers_del_write(fd_info->watchers, i); - collection_remove_cnx(fd_info->collection, cnx); hash_remove(fd_info->hash_sources, cnx); + list_remove(&cnx->proto->timeouts, cnx); + collection_remove_cnx(fd_info->collection, cnx); } else { if (timeout < next_timeout) next_timeout = timeout; } @@ -164,10 +220,18 @@ void udp_timeouts(struct loop_info* fd_info) fd_info->next_timeout = next_timeout; } + /* Mark the connection was active */ static void mark_active(struct connection* cnx) { cnx->last_active = time(NULL); + + dl_list* list = &cnx->proto->timeouts; + + list_remove(list, cnx); + list_push(list, cnx); + + list_dump(); }