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.
This commit is contained in:
Simon Kelley
2025-01-07 20:53:03 +00:00
parent 6656790f24
commit 63dc6eb316

View File

@@ -770,7 +770,7 @@ int retry_send(ssize_t rc)
rw = 2 -> write once rw = 2 -> write once
rw = 3 -> read 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. This indicates a timeout of a TCP socket.
*/ */
int read_write(int fd, unsigned char *packet, int size, int rw) int read_write(int fd, unsigned char *packet, int size, int rw)
@@ -779,7 +779,6 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
for (done = 0; done < size; done += n) for (done = 0; done < size; done += n)
{ {
do {
if (rw & 1) if (rw & 1)
n = read(fd, &packet[done], (size_t)(size - done)); n = read(fd, &packet[done], (size_t)(size - done));
else else
@@ -788,19 +787,25 @@ int read_write(int fd, unsigned char *packet, int size, int rw)
if (n == 0) if (n == 0)
return 0; return 0;
if (n == -1 && errno == EINTR) if (n == -1)
{
n = 0; /* don't mess with counter when we loop. */
if (errno == EINTR || errno == ENOMEM || errno == ENOBUFS)
continue; continue;
if (errno == EAGAIN || errno == EWOULDBLOCK)
{
/* "once" variant */ /* "once" variant */
if ((rw & 2) && n != size) if (rw & 2)
return 0; return 0;
} while (n == -1 && (errno == EINTR || errno == ENOMEM || errno == ENOBUFS || continue;
errno == EAGAIN || errno == EWOULDBLOCK)); }
if (n == -1)
return 0; return 0;
} }
}
return 1; return 1;
} }