From 63dc6eb3164fab26d3606eb500fd56502a6e24aa Mon Sep 17 00:00:00 2001 From: Simon Kelley Date: Tue, 7 Jan 2025 20:53:03 +0000 Subject: [PATCH] Fix read_write() changes for TCP timeout. I misread the man page for socket(7) and TCP timeouts. A timeout generates a -1 return and EAGAIN errno, NOT a short read. Short reads are legit, and aborting when they are seen creates hard-to-reproduce errors. --- src/util.c | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/util.c b/src/util.c index ffed03b..16858f3 100644 --- a/src/util.c +++ b/src/util.c @@ -770,7 +770,7 @@ int retry_send(ssize_t rc) rw = 2 -> write once rw = 3 -> read once - "once" fail if all the data doesn't arrive/go in a single read/write. + "once" fails on EAGAIN, as this a timeout. This indicates a timeout of a TCP socket. */ int read_write(int fd, unsigned char *packet, int size, int rw) @@ -779,29 +779,34 @@ int read_write(int fd, unsigned char *packet, int size, int rw) for (done = 0; done < size; done += n) { - do { - if (rw & 1) - n = read(fd, &packet[done], (size_t)(size - done)); - else - n = write(fd, &packet[done], (size_t)(size - done)); - - if (n == 0) - return 0; - - if (n == -1 && errno == EINTR) - continue; - - /* "once" variant */ - if ((rw & 2) && n != size) - return 0; - - } while (n == -1 && (errno == EINTR || errno == ENOMEM || errno == ENOBUFS || - errno == EAGAIN || errno == EWOULDBLOCK)); + if (rw & 1) + n = read(fd, &packet[done], (size_t)(size - done)); + else + n = write(fd, &packet[done], (size_t)(size - done)); - if (n == -1) + if (n == 0) return 0; + + if (n == -1) + { + n = 0; /* don't mess with counter when we loop. */ + + if (errno == EINTR || errno == ENOMEM || errno == ENOBUFS) + continue; + + if (errno == EAGAIN || errno == EWOULDBLOCK) + { + /* "once" variant */ + if (rw & 2) + return 0; + + continue; + } + + return 0; + } } - + return 1; }