From eba03547a52d88b8d2b6bc8fc647adb4ba9a86d2 Mon Sep 17 00:00:00 2001 From: Nick Hainke Date: Wed, 20 Jul 2022 13:30:00 +0200 Subject: [PATCH] network: add timeout for client connections Somtimes client connetions will not close therfore add a timeout. Add a new timer that checks every 5s if we did not receive anything from a client for (default) 60s. Can be configured via client_timeout. Code is based on the work of ptpt52. Signed-off-by: Nick Hainke --- CONFIGURE.md | 1 + dawn-config | 1 + src/include/datastorage.h | 1 + src/include/tcpsocket.h | 6 ++++++ src/network/tcpsocket.c | 19 +++++++++++++++++++ src/utils/dawn_uci.c | 3 +++ src/utils/msghandler.c | 4 ++++ src/utils/ubus.c | 15 +++++++++++++++ 8 files changed, 50 insertions(+) diff --git a/CONFIGURE.md b/CONFIGURE.md index 82b0f65..a653fbe 100644 --- a/CONFIGURE.md +++ b/CONFIGURE.md @@ -263,6 +263,7 @@ grep 'CONFIG-T:' `find . -type f -name "*.[ch]"`|sed 's/^.*CONFIG-.: *\(.*\)$/|\ --> |Parameter|Purpose|Notes [Default is bracketed]| |---------|-------|-----| +|client_timeout|Timespan until a client is seen as disconnected|[60]| |remove_ap|Timer to remove expired AP entries from core data set|[460]| |remove_client|Timer to remove expired client entries from core data set|[15]| |remove_probe|Timer to remove expired PROBE and BEACON entries from core data set|[30]| diff --git a/dawn-config b/dawn-config index dbfafc1..5e226a3 100644 --- a/dawn-config +++ b/dawn-config @@ -17,6 +17,7 @@ config hostapd option hostapd_dir '/var/run/hostapd' config times + option client_timeout '60' option update_client '10' option remove_client '15' option remove_probe '30' diff --git a/src/include/datastorage.h b/src/include/datastorage.h index 9b6e995..eefc95c 100644 --- a/src/include/datastorage.h +++ b/src/include/datastorage.h @@ -109,6 +109,7 @@ struct time_config_s { time_t update_tcp_con; // Refresh network connections time_t update_chan_util; // Refresh per radio / SSID channel util info time_t update_beacon_reports; // Request BEACON from capable clients + time_t client_timeout; // Check for client timeouts. }; struct local_config_s { diff --git a/src/include/tcpsocket.h b/src/include/tcpsocket.h index 39e21a7..1fb335d 100644 --- a/src/include/tcpsocket.h +++ b/src/include/tcpsocket.h @@ -5,6 +5,7 @@ #include #define ARRAY_NETWORK_LEN 50 +#define CHECK_CLIENT_TIMEOUT 5 struct network_con_s { struct list_head list; @@ -36,6 +37,11 @@ int run_server(int port); */ void send_tcp(char *msg); +/** + * Check sockets for client timeouts. + */ +void check_client_timeout(int timeout); + /** * Debug message. */ diff --git a/src/network/tcpsocket.c b/src/network/tcpsocket.c index 91bc452..b539286 100644 --- a/src/network/tcpsocket.c +++ b/src/network/tcpsocket.c @@ -14,6 +14,7 @@ #define HEADER_SIZE sizeof(uint32_t) LIST_HEAD(tcp_sock_list); +LIST_HEAD(cli_list); struct network_con_s *tcp_list_contains_address(struct sockaddr_in entry); @@ -27,6 +28,7 @@ enum socket_read_status { }; struct client { + struct list_head list; struct sockaddr_in sin; struct ustream_fd s; @@ -36,6 +38,7 @@ struct client { enum socket_read_status state; // messge read state uint32_t final_len; // full message length uint32_t curr_len; // bytes read so far + time_t time_alive; }; @@ -48,6 +51,7 @@ static void client_close(struct ustream *s) { ustream_free(s); dawn_unregmem(s); close(cl->s.fd.fd); + list_del(&cl->list); dawn_free(cl); cl = NULL; } @@ -199,6 +203,7 @@ static void client_read_cb(struct ustream *s, int bytes) { cl->final_len = 0; dawn_free(cl->str); cl->str = NULL; + cl->time_alive = time(0); } } @@ -228,6 +233,8 @@ static void server_cb(struct uloop_fd *fd, unsigned int events) { cl->s.stream.notify_read = client_read_cb; cl->s.stream.notify_state = client_notify_state; cl->s.stream.notify_write = client_notify_write; + cl->time_alive = time(0); + list_add(&cl->list, &cli_list); ustream_fd_init(&cl->s, sfd); dawn_regmem(&cl->s); next_client = NULL; // TODO: Why is this here? To avoid resetting if above return happens? @@ -422,6 +429,18 @@ void send_tcp(char *msg) { } } +void check_client_timeout(int timeout) { + struct client *cl, *tmp; + time_t now = time(0); + list_for_each_entry_safe(cl, tmp, &cli_list, list) + { + if (now - cl->time_alive > timeout || now - cl->time_alive < -timeout) { + dawnlog_debug("Ustream client_close: timeout=%d\n", (int)(now - cl->time_alive)); + client_close(&cl->s.stream); + } + } +} + struct network_con_s* tcp_list_contains_address(struct sockaddr_in entry) { struct network_con_s *con; diff --git a/src/utils/dawn_uci.c b/src/utils/dawn_uci.c index ff776a2..82873b3 100644 --- a/src/utils/dawn_uci.c +++ b/src/utils/dawn_uci.c @@ -79,6 +79,7 @@ struct time_config_s uci_get_time_config() { .update_tcp_con = 10, .update_chan_util = 5, .update_beacon_reports = 20, + .client_timeout = 60, }; dawnlog_debug_func("Entering..."); @@ -105,6 +106,8 @@ struct time_config_s uci_get_time_config() { DAWN_SET_CONFIG_TIME(ret, s, update_chan_util); //CONFIG-T: update_beacon_reports|Timer to ask all connected clients for a new BEACON REPORT|[20] DAWN_SET_CONFIG_TIME(ret, s, update_beacon_reports); + //CONFIG-T: client_timeout|Timespan to check if a client timed out|[60] + DAWN_SET_CONFIG_TIME(ret, s, client_timeout); return ret; } } diff --git a/src/utils/msghandler.c b/src/utils/msghandler.c index 608cd2f..3827662 100644 --- a/src/utils/msghandler.c +++ b/src/utils/msghandler.c @@ -656,6 +656,7 @@ enum { UCI_UPDATE_TCP_CON, UCI_UPDATE_CHAN_UTIL, UCI_UPDATE_BEACON_REPORTS, + UCI_CLIENT_TIMEOUT, __UCI_TIMES_MAX, }; @@ -713,6 +714,7 @@ static const struct blobmsg_policy uci_times_policy[__UCI_TIMES_MAX] = { [UCI_UPDATE_TCP_CON] = {.name = "update_tcp_con", .type = BLOBMSG_TYPE_INT32}, [UCI_UPDATE_CHAN_UTIL] = {.name = "update_chan_util", .type = BLOBMSG_TYPE_INT32}, [UCI_UPDATE_BEACON_REPORTS] = {.name = "update_beacon_reports", .type = BLOBMSG_TYPE_INT32}, + [UCI_CLIENT_TIMEOUT] = {.name = "client_timeout", .type = BLOBMSG_TYPE_INT32}, }; static void set_uci_item(char* m, struct blob_attr* a) @@ -895,6 +897,8 @@ static int handle_uci_config(struct blob_attr* msg) { set_uci_item("dawn.@times[0].update_beacon_reports=%d", tb_times[UCI_UPDATE_BEACON_REPORTS]); + set_uci_item("dawn.@times[0].client_timeout=%d", tb_times[UCI_CLIENT_TIMEOUT]); + uci_reset(); dawn_metric = uci_get_dawn_metric(); timeout_config = uci_get_time_config(); diff --git a/src/utils/ubus.c b/src/utils/ubus.c index 995b2f8..4280410 100644 --- a/src/utils/ubus.c +++ b/src/utils/ubus.c @@ -23,6 +23,8 @@ void update_clients(struct uloop_timeout *t); void update_tcp_connections(struct uloop_timeout *t); +void check_client_timeouts(struct uloop_timeout *t); + void update_channel_utilization(struct uloop_timeout *t); void run_server_update(struct uloop_timeout *t); @@ -38,6 +40,9 @@ struct uloop_timeout hostapd_timer = { struct uloop_timeout tcp_con_timer = { .cb = update_tcp_connections }; +struct uloop_timeout client_timeout_timer = { + .cb = check_client_timeouts +}; struct uloop_timeout channel_utilization_timer = { .cb = update_channel_utilization }; @@ -1148,11 +1153,20 @@ void update_tcp_connections(struct uloop_timeout *t) { uloop_timeout_set(&tcp_con_timer, timeout_config.update_tcp_con * 1000); } +void check_client_timeouts(struct uloop_timeout *t) { + dawnlog_debug_func("Entering..."); + + check_client_timeout(timeout_config.client_timeout); + + uloop_timeout_set(&client_timeout_timer, CHECK_CLIENT_TIMEOUT * 1000); +} + void start_tcp_con_update() { dawnlog_debug_func("Entering..."); // update connections uloop_timeout_add(&tcp_con_timer); // callback = update_tcp_connections + uloop_timeout_add(&client_timeout_timer); // callback = client_timeout } void update_hostapd_sockets(struct uloop_timeout *t) { @@ -1888,6 +1902,7 @@ int uci_send_via_network() blobmsg_add_u32(&b, "update_tcp_con", timeout_config.update_tcp_con); blobmsg_add_u32(&b, "update_chan_util", timeout_config.update_chan_util); blobmsg_add_u32(&b, "update_beacon_reports", timeout_config.update_beacon_reports); + blobmsg_add_u32(&b, "client_timeout", timeout_config.client_timeout); blobmsg_close_table(&b, times); send_blob_attr_via_network(b.head, "uci");