From e3d00682bcad2e0f26ee15b1c73d5da022b18786 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Fri, 6 Oct 2023 14:59:22 +0200 Subject: [PATCH] sock/udp: work around gnrc_sock_recv() returning early timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sock_udp_recv_buf_aux() sometimes will return -ETIMEDOUT before the given timeout has expired (e.g. 28798µs instead of 160000µs). This messes with many assumptions and breaks protocols that rely on the timeout. Until we have a proper fix, add this workaround. --- sys/net/gnrc/sock/udp/gnrc_sock_udp.c | 31 ++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/sys/net/gnrc/sock/udp/gnrc_sock_udp.c b/sys/net/gnrc/sock/udp/gnrc_sock_udp.c index dfffcef6e1..2d8f4a6abe 100644 --- a/sys/net/gnrc/sock/udp/gnrc_sock_udp.c +++ b/sys/net/gnrc/sock/udp/gnrc_sock_udp.c @@ -237,6 +237,16 @@ static bool _accept_remote(const sock_udp_t *sock, const udp_hdr_t *hdr, return true; } +static uint32_t _now_us(void) +{ +#ifdef MODULE_ZTIMER_USEC + return ztimer_now(ZTIMER_USEC); +#endif +#ifdef MODULE_ZTIMER_MSEC + return ztimer_now(ZTIMER_MSEC) * US_PER_MS; +#endif +} + ssize_t sock_udp_recv_buf_aux(sock_udp_t *sock, void **data, void **buf_ctx, uint32_t timeout, sock_udp_ep_t *remote, sock_udp_aux_rx_t *aux) @@ -274,7 +284,26 @@ ssize_t sock_udp_recv_buf_aux(sock_udp_t *sock, void **data, void **buf_ctx, _aux.rssi = &aux->rssi; } #endif - res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp, &_aux); + unsigned now = _now_us(); + while (1) { + res = gnrc_sock_recv((gnrc_sock_reg_t *)sock, &pkt, timeout, &tmp, &_aux); + + if (res != -ETIMEDOUT) { + break; + } + + /* HACK: gnrc_sock_recv() sometimes returns -ETIMEDOUT too early */ + uint32_t time_elapsed = _now_us() - now; + if (time_elapsed < (timeout - timeout/10)) { + DEBUG("gnrc_sock_udp: timeout happened %"PRIu32" µs early\n", + timeout - time_elapsed); + timeout -= time_elapsed; + now = _now_us(); + continue; + } + break; + } + if (res < 0) { return res; }