From 56d12423e3884c4089a4ee191423ea5a947d985c Mon Sep 17 00:00:00 2001 From: Zdenek Dohnal Date: Thu, 5 Mar 2026 09:26:29 +0100 Subject: [PATCH 1/2] tls-gnutls.c: Do not check for errno after I/O operations Based on gnutls_record_send/recv man pages, we should use the return value of the functions as indicator what happened in the function and do not look into errno at all. Checking the errno value caused infinity loop in cupsd on busy servers if there were enough connection errors when cupsd wrote the response. The patch is provided by Paul Zirnik from SUSE - thank you for the patch! Fixes #827 --- cups/tls-gnutls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cups/tls-gnutls.c b/cups/tls-gnutls.c index 2fe7ef196..86ef51d79 100644 --- a/cups/tls-gnutls.c +++ b/cups/tls-gnutls.c @@ -1613,7 +1613,7 @@ _httpTLSRead(http_t *http, // I - Connection to server result = gnutls_record_recv(http->tls, buf, (size_t)len); - if (result < 0 && !errno) + if (result < 0) { // Convert GNU TLS error to errno value... switch (result) @@ -2022,7 +2022,7 @@ _httpTLSWrite(http_t *http, // I - Connection to server result = gnutls_record_send(http->tls, buf, (size_t)len); - if (result < 0 && !errno) + if (result < 0) { // Convert GNU TLS error to errno value... switch (result) From eebaba135e8f3a62291d924b2c323756d2f65a5a Mon Sep 17 00:00:00 2001 From: Zdenek Dohnal Date: Thu, 5 Mar 2026 14:33:27 +0100 Subject: [PATCH 2/2] tls-gnutls.c: Handle rehandshake error in `_httpTLSRead` Per GNUTLS manual, `gnutls_record_recv()` can get GNUTLS_E_REHANDSHAKE and if it is HTTP client, we should not close the connection and ignore the error. The server can terminate the connection as before. --- cups/tls-gnutls.c | 78 ++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 34 deletions(-) diff --git a/cups/tls-gnutls.c b/cups/tls-gnutls.c index 86ef51d79..104997105 100644 --- a/cups/tls-gnutls.c +++ b/cups/tls-gnutls.c @@ -1613,25 +1613,37 @@ _httpTLSRead(http_t *http, // I - Connection to server result = gnutls_record_recv(http->tls, buf, (size_t)len); - if (result < 0) + if (result >= 0) + return (result); + + // Convert GNU TLS error to errno value... + switch (result) { - // Convert GNU TLS error to errno value... - switch (result) - { - case GNUTLS_E_INTERRUPTED : - errno = EINTR; - break; + case GNUTLS_E_INTERRUPTED : + errno = EINTR; + break; - case GNUTLS_E_AGAIN : - errno = EAGAIN; - break; + case GNUTLS_E_AGAIN : + errno = EAGAIN; + break; - default : - errno = EPIPE; - break; - } + case GNUTLS_E_REHANDSHAKE : + // if used in client, ignore the error + if (http->mode == _HTTP_MODE_CLIENT) + { + errno = 0; + result = 0; + } + else + { + // terminate the session as server + errno = EPIPE; + } + break; - result = -1; + default : + errno = EPIPE; + break; } return ((int)result); @@ -2022,30 +2034,28 @@ _httpTLSWrite(http_t *http, // I - Connection to server result = gnutls_record_send(http->tls, buf, (size_t)len); - if (result < 0) - { - // Convert GNU TLS error to errno value... - switch (result) - { - case GNUTLS_E_INTERRUPTED : - errno = EINTR; - break; + DEBUG_printf("5_httpTLSWrite: gnutls_record_send returns %d.", (int)result); - case GNUTLS_E_AGAIN : - errno = EAGAIN; - break; + if (result >= 0) + return (result); - default : - errno = EPIPE; - break; - } + // Convert GNU TLS error to errno value... + switch (result) + { + case GNUTLS_E_INTERRUPTED : + errno = EINTR; + break; - result = -1; - } + case GNUTLS_E_AGAIN : + errno = EAGAIN; + break; - DEBUG_printf("5_httpTLSWrite: Returning %d.", (int)result); + default : + errno = EPIPE; + break; + } - return ((int)result); + return (-1); }