From cd664574f12b465a61924e9a032a56f191db281e Mon Sep 17 00:00:00 2001 From: yrutschle Date: Wed, 27 Apr 2022 17:28:13 +0200 Subject: [PATCH] manage timeout with lists instead of linear searches --- udp-listener.c | 80 ++++++++------------------------------------------ 1 file changed, 12 insertions(+), 68 deletions(-) diff --git a/udp-listener.c b/udp-listener.c index 3efcdcb..ef27311 100644 --- a/udp-listener.c +++ b/udp-listener.c @@ -27,14 +27,6 @@ #include "sslh-conf.h" #include "udp-listener.h" -/* returns date at which this socket times out. */ -static int udp_timeout(struct connection* cnx) -{ - if (cnx->type != SOCK_DGRAM) return 0; /* Not a UDP connection */ - - return cnx->proto->udp_timeout + cnx->last_active; -} - /* Incoming connections are of course all received on a single socket. Create a * hash that associates (incoming sockaddr) => struct connection*, so finding * the connection related to an incoming packet is fast. @@ -148,76 +140,30 @@ static void list_remove(dl_list* list, struct connection* cnx) 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 - * search through connections if that timeout actually happened. If the - * connection that would have timed out has had activity, it doesn't matter: we - * go through connections to find the next timeout, which was needed anyway. +/* Timeouts are managed with one list for each protocol. Whenever a connection + * is active, it gets moved to the end of the list. Each call will pop the + * first elements that have timed out and free their resources. * * This gets called every time a UDP packet is received from the outside, i.e. * every time we might need to free up resources. If no packets come in, we * don't time out anything, as we don't need the resources. - * - * TODO: use a better algorithm to avoid going through all connections each - * time. - * * */ void udp_timeouts(struct loop_info* fd_info) { time_t now = time(NULL); - if (now < fd_info->next_timeout) return; + for (int i = 0; i < cfg.protocols_len; i++) { + struct connection *cnx = cfg.protocols[i].timeouts.head; + while (cnx && (now - cnx->last_active > cfg.protocols[i].udp_timeout)) { + print_message(msg_fd, "timed out UDP %d\n", cnx->target_sock); + close(cnx->target_sock); + hash_remove(fd_info->hash_sources, cnx); + list_remove(&cnx->proto->timeouts, cnx); + tidy_connection(cnx, fd_info); - time_t next_timeout = INT_MAX; - - for (int i = 0; i <= watchers_maxfd(fd_info->watchers); i++) { - /* if it's either in read or write set, there is a connection - * behind that file descriptor */ - struct connection* cnx = collection_get_cnx_from_fd(fd_info->collection, i); - if (cnx) { - time_t timeout = udp_timeout(cnx); - if (!timeout) continue; /* Not a UDP connection */ - if (cnx && (timeout <= now)) { - print_message(msg_fd, "timed out UDP %d\n", cnx->target_sock); - close(cnx->target_sock); - watchers_del_read(fd_info->watchers, i); - watchers_del_write(fd_info->watchers, i); - 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; - } + cnx = cfg.protocols[i].timeouts.head; } } - - if (next_timeout != INT_MAX) - fd_info->next_timeout = next_timeout; } @@ -230,8 +176,6 @@ static void mark_active(struct connection* cnx) list_remove(list, cnx); list_push(list, cnx); - - list_dump(); }