The branch main has been updated by des:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=da4d1ced75f3be17f8b089a364f642a04eb0d466

commit da4d1ced75f3be17f8b089a364f642a04eb0d466
Author:     Dag-Erling Smørgrav <[email protected]>
AuthorDate: 2026-06-29 15:53:56 +0000
Commit:     Dag-Erling Smørgrav <[email protected]>
CommitDate: 2026-06-29 15:53:56 +0000

    Revert "libfetch: Overhaul socket read / write"
    
    This reverts commit 298f37a71ae6d9f2cb0c2abd4ff2887e81e0942c.
---
 lib/libfetch/common.c | 206 ++++++++++++++++++++------------------------------
 lib/libfetch/common.h |   4 +-
 2 files changed, 83 insertions(+), 127 deletions(-)

diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c
index c5fb45f70da2..88b5e5a2f096 100644
--- a/lib/libfetch/common.c
+++ b/lib/libfetch/common.c
@@ -1253,9 +1253,13 @@ fetch_ssl(conn_t *conn, const struct url *URL, int 
verbose)
 #endif
 }
 
+#define FETCH_READ_WAIT                -2
+#define FETCH_READ_ERROR       -1
+#define FETCH_READ_DONE                 0
+
 #ifdef WITH_SSL
 static ssize_t
-fetch_ssl_read(SSL *ssl, void *buf, size_t len)
+fetch_ssl_read(SSL *ssl, char *buf, size_t len)
 {
        ssize_t rlen;
        int ssl_err;
@@ -1263,57 +1267,43 @@ fetch_ssl_read(SSL *ssl, void *buf, size_t len)
        rlen = SSL_read(ssl, buf, len);
        if (rlen < 0) {
                ssl_err = SSL_get_error(ssl, rlen);
-               switch (ssl_err) {
-               case SSL_ERROR_ZERO_RETURN:
-                       return (0);
-               case SSL_ERROR_WANT_READ:
-                       errno = EAGAIN;
-                       return (-1);
-               case SSL_ERROR_SYSCALL:
-                       return (-1);
-               default:
-                       errno = EPROTO;
-                       return (-1);
+               if (ssl_err == SSL_ERROR_WANT_READ ||
+                   ssl_err == SSL_ERROR_WANT_WRITE) {
+                       return (FETCH_READ_WAIT);
+               } else {
+                       ERR_print_errors_fp(stderr);
+                       return (FETCH_READ_ERROR);
                }
        }
        return (rlen);
 }
+#endif
 
 static ssize_t
-fetch_ssl_write(SSL *ssl, void *buf, size_t len)
+fetch_socket_read(int sd, char *buf, size_t len)
 {
-       ssize_t wlen;
-       int ssl_err;
+       ssize_t rlen;
 
-       wlen = SSL_write(ssl, buf, len);
-       if (wlen < 0) {
-               ssl_err = SSL_get_error(ssl, wlen);
-               switch (ssl_err) {
-               case SSL_ERROR_ZERO_RETURN:
-                       return (0);
-               case SSL_ERROR_WANT_WRITE:
-                       errno = EAGAIN;
-                       return (-1);
-               case SSL_ERROR_SYSCALL:
-                       return (-1);
-               default:
-                       errno = EPROTO;
-                       return (-1);
+       rlen = read(sd, buf, len);
+       if (rlen < 0) {
+               if (errno == EAGAIN || (errno == EINTR && fetchRestartCalls)) {
+                       return (FETCH_READ_WAIT);
+               } else {
+                       return (FETCH_READ_ERROR);
                }
        }
-       return (wlen);
+       return (rlen);
 }
-#endif
 
 /*
- * Read from a connection w/ timeout
+ * Read a character from a connection w/ timeout
  */
 ssize_t
-fetch_read(conn_t *conn, void *buf, size_t len)
+fetch_read(conn_t *conn, char *buf, size_t len)
 {
        struct timeval now, timeout, delta;
        struct pollfd pfd;
-       ssize_t rlen, total;
+       ssize_t rlen;
        int deltams;
 
        if (fetchTimeout > 0) {
@@ -1322,10 +1312,10 @@ fetch_read(conn_t *conn, void *buf, size_t len)
        }
 
        deltams = INFTIM;
+       memset(&pfd, 0, sizeof pfd);
        pfd.fd = conn->sd;
-       pfd.events = POLLIN;
+       pfd.events = POLLIN | POLLERR;
 
-       total = 0;
        for (;;) {
                /*
                 * The socket is non-blocking.  Instead of the canonical
@@ -1333,8 +1323,8 @@ fetch_read(conn_t *conn, void *buf, size_t len)
                 *
                 * 1) call read() or SSL_read().
                 * 2) if we received some data, return it.
-                * 3) if read() or SSL_read() signaled EOF, return.
-                * 4) if an error occurred, return -1.
+                * 3) if an error occurred, return -1.
+                * 4) if read() or SSL_read() signaled EOF, return.
                 * 5) if we did not receive any data but we're not at EOF,
                 *    call poll().
                 *
@@ -1351,26 +1341,14 @@ fetch_read(conn_t *conn, void *buf, size_t len)
                        rlen = fetch_ssl_read(conn->ssl, buf, len);
                else
 #endif
-                       rlen = read(conn->sd, buf, len);
-               if (rlen > 0) {
-                       /* something was read */
-                       total += rlen;
-                       len -= rlen;
-                       if (len == 0)
-                               break;
-                       /* a partial read is success */
-                       break;
-               } else if (rlen == 0) {
-                       /* connection closed */
+                       rlen = fetch_socket_read(conn->sd, buf, len);
+               if (rlen >= 0) {
                        break;
-               } else if (errno != EAGAIN) {
-                       /* error */
-                       if (errno == EINTR && fetchRestartCalls)
-                               continue;
+               } else if (rlen == FETCH_READ_ERROR) {
                        fetch_syserr();
-                       break;
+                       return (-1);
                }
-               /* check what's left of our timeout */
+               // assert(rlen == FETCH_READ_WAIT);
                if (fetchTimeout > 0) {
                        gettimeofday(&now, NULL);
                        if (!timercmp(&timeout, &now, >)) {
@@ -1382,19 +1360,16 @@ fetch_read(conn_t *conn, void *buf, size_t len)
                        deltams = delta.tv_sec * 1000 +
                            delta.tv_usec / 1000;
                }
-               /* wait for the socket to become readable */
+               errno = 0;
+               pfd.revents = 0;
                if (poll(&pfd, 1, deltams) < 0) {
-                       if (errno == EAGAIN)
-                               continue;
                        if (errno == EINTR && fetchRestartCalls)
                                continue;
-                       break;
+                       fetch_syserr();
+                       return (-1);
                }
        }
-       /* a partial read is success */
-       if (rlen < 0 && total == 0)
-               return (-1);
-       return (total);
+       return (rlen);
 }
 
 
@@ -1451,7 +1426,7 @@ fetch_getln(conn_t *conn)
  * Write to a connection w/ timeout
  */
 ssize_t
-fetch_write(conn_t *conn, const void *buf, size_t len)
+fetch_write(conn_t *conn, const char *buf, size_t len)
 {
        struct iovec iov;
 
@@ -1472,65 +1447,17 @@ fetch_writev(conn_t *conn, struct iovec *iov, int 
iovcnt)
        ssize_t wlen, total;
        int deltams;
 
-       if (fetchTimeout > 0) {
+       memset(&pfd, 0, sizeof pfd);
+       if (fetchTimeout) {
+               pfd.fd = conn->sd;
+               pfd.events = POLLOUT | POLLERR;
                gettimeofday(&timeout, NULL);
                timeout.tv_sec += fetchTimeout;
        }
 
-       deltams = INFTIM;
-       pfd.fd = conn->sd;
-       pfd.events = POLLOUT;
-
        total = 0;
-       for (;;) {
-               /*
-                * The socket is non-blocking.  Instead of the canonical
-                * poll() -> write(), we do the following:
-                *
-                * 1) call write() or SSL_write().
-                * 2) if we wrote everything, return success.
-                * 3) if write() or SSL_write() signaled EOF before we
-                *    wrote everything, return -1.
-                * 4) if an error occurred, return -1.
-                * 5) if we did not write everything but we're not at EOF,
-                *    call poll().
-                */
-#ifdef WITH_SSL
-               if (conn->ssl != NULL) {
-                       wlen = fetch_ssl_write(conn->ssl,
-                           iov->iov_base, iov->iov_len);
-               } else
-#endif
-                       wlen = writev(conn->sd, iov, iovcnt);
-               if (wlen > 0) {
-                       /* something was written */
-                       total += wlen;
-                       /* skip iovs which were completely written */
-                       while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
-                               wlen -= iov->iov_len;
-                               iov++;
-                               iovcnt--;
-                       }
-                       /* are we done? */
-                       if (iovcnt == 0)
-                               break;
-                       /* skip written portion of current iov */
-                       iov->iov_len -= wlen;
-                       iov->iov_base = __DECONST(char *, iov->iov_base) + wlen;
-                       /* a partial write is incomplete */
-                       continue;
-               } else if (wlen == 0) {
-                       /* connection closed */
-                       break;
-               } else if (errno != EAGAIN) {
-                       /* error */
-                       if (errno == EINTR && fetchRestartCalls)
-                               continue;
-                       fetch_syserr();
-                       break;
-               }
-               /* check what's left of our timeout */
-               if (fetchTimeout > 0) {
+       while (iovcnt > 0) {
+               while (fetchTimeout && pfd.revents == 0) {
                        gettimeofday(&now, NULL);
                        if (!timercmp(&timeout, &now, >)) {
                                errno = ETIMEDOUT;
@@ -1540,19 +1467,48 @@ fetch_writev(conn_t *conn, struct iovec *iov, int 
iovcnt)
                        timersub(&timeout, &now, &delta);
                        deltams = delta.tv_sec * 1000 +
                            delta.tv_usec / 1000;
+                       errno = 0;
+                       pfd.revents = 0;
+                       if (poll(&pfd, 1, deltams) < 0) {
+                               /* POSIX compliance */
+                               if (errno == EAGAIN)
+                                       continue;
+                               if (errno == EINTR && fetchRestartCalls)
+                                       continue;
+                               return (-1);
+                       }
                }
-               /* wait for the socket to become writeable */
-               if (poll(&pfd, 1, deltams) < 0) {
-                       if (errno == EAGAIN)
-                               continue;
+               errno = 0;
+#ifdef WITH_SSL
+               if (conn->ssl != NULL)
+                       wlen = SSL_write(conn->ssl,
+                           iov->iov_base, iov->iov_len);
+               else
+#endif
+                       wlen = writev(conn->sd, iov, iovcnt);
+               if (wlen == 0) {
+                       /* we consider a short write a failure */
+                       /* XXX perhaps we shouldn't in the SSL case */
+                       errno = EPIPE;
+                       fetch_syserr();
+                       return (-1);
+               }
+               if (wlen < 0) {
                        if (errno == EINTR && fetchRestartCalls)
                                continue;
                        return (-1);
                }
+               total += wlen;
+               while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
+                       wlen -= iov->iov_len;
+                       iov++;
+                       iovcnt--;
+               }
+               if (iovcnt > 0) {
+                       iov->iov_len -= wlen;
+                       iov->iov_base = __DECONST(char *, iov->iov_base) + wlen;
+               }
        }
-       /* a partial write is failure */
-       if (iovcnt > 0)
-               return (-1);
        return (total);
 }
 
diff --git a/lib/libfetch/common.h b/lib/libfetch/common.h
index 479c5e03c0d1..06089aae5451 100644
--- a/lib/libfetch/common.h
+++ b/lib/libfetch/common.h
@@ -119,9 +119,9 @@ conn_t              *fetch_ref(conn_t *);
 int             fetch_ssl_cb_verify_crt(int, X509_STORE_CTX*);
 #endif
 int             fetch_ssl(conn_t *, const struct url *, int);
-ssize_t                 fetch_read(conn_t *, void *, size_t);
+ssize_t                 fetch_read(conn_t *, char *, size_t);
 int             fetch_getln(conn_t *);
-ssize_t                 fetch_write(conn_t *, const void *, size_t);
+ssize_t                 fetch_write(conn_t *, const char *, size_t);
 ssize_t                 fetch_writev(conn_t *, struct iovec *, int);
 int             fetch_putln(conn_t *, const char *, size_t);
 int             fetch_close(conn_t *);

Reply via email to