From: Heiko Schlittermann (HS12-RIPE) Date: Tue, 3 Mar 2020 07:06:22 +0000 (+0100) Subject: Revert "GnuTLS: remove GNUTLS_E_AGAIN handling" X-Git-Url: https://git.exim.org/users/heiko/exim.git/commitdiff_plain/05c3a5a25488ae73043364a87dcf54c907a655d4 Revert "GnuTLS: remove GNUTLS_E_AGAIN handling" This reverts commit 0b049796b89a59fc322119b54199d92c404ef687. Thanks to Andreas Metzler for pointing me to: https://gitlab.com/gnutls/gnutls/issues/644#note_123363338 --- diff --git a/src/src/tls-gnu.c b/src/src/tls-gnu.c index 90c4cd024..72f178717 100644 --- a/src/src/tls-gnu.c +++ b/src/src/tls-gnu.c @@ -2513,7 +2513,7 @@ sigalrm_seen = FALSE; if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout); do rc = gnutls_handshake(state->session); -while (rc == GNUTLS_E_INTERRUPTED && !sigalrm_seen); +while (rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED && !sigalrm_seen); ALARM_CLR(0); if (rc != GNUTLS_E_SUCCESS) @@ -2993,7 +2993,7 @@ sigalrm_seen = FALSE; ALARM(ob->command_timeout); do rc = gnutls_handshake(state->session); -while (rc == GNUTLS_E_INTERRUPTED && !sigalrm_seen); +while (rc == GNUTLS_E_AGAIN || rc == GNUTLS_E_INTERRUPTED && !sigalrm_seen); ALARM_CLR(0); if (rc != GNUTLS_E_SUCCESS) @@ -3157,7 +3157,10 @@ DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(session=%p, buffer=%p, buf sigalrm_seen = FALSE; if (smtp_receive_timeout > 0) ALARM(smtp_receive_timeout); -inbytes = gnutls_record_recv(state->session, state->xfer_buffer, MIN(ssl_xfer_buffer_size, lim)); +do + inbytes = gnutls_record_recv(state->session, state->xfer_buffer, + MIN(ssl_xfer_buffer_size, lim)); +while (inbytes == GNUTLS_E_AGAIN); if (smtp_receive_timeout > 0) ALARM_CLR(0); @@ -3314,7 +3317,9 @@ DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(session=%p, buffer=%p, len=" SIZE_T_FMT ")\n", state->session, buff, len); -inbytes = gnutls_record_recv(state->session, buff, len); +do + inbytes = gnutls_record_recv(state->session, buff, len); +while (inbytes == GNUTLS_E_AGAIN); if (inbytes > 0) return inbytes; if (inbytes == 0) @@ -3375,7 +3380,9 @@ while (left > 0) DEBUG(D_tls) debug_printf("gnutls_record_send(session=%p, buffer=%p, left=" SIZE_T_FMT ")\n", state->session, buff, left); - outbytes = gnutls_record_send(state->session, buff, left); + do + outbytes = gnutls_record_send(state->session, buff, left); + while (outbytes == GNUTLS_E_AGAIN); DEBUG(D_tls) debug_printf("outbytes=" SSIZE_T_FMT "\n", outbytes); @@ -3407,12 +3414,21 @@ if (len > INT_MAX) if (!more && state->corked) { DEBUG(D_tls) debug_printf("gnutls_record_uncork(session=%p)\n", state->session); - outbytes = gnutls_record_uncork(state->session, 0); + do + /* We can't use GNUTLS_RECORD_WAIT here, as it retries on + GNUTLS_E_AGAIN || GNUTLS_E_INTR, which would break our timeout set by alarm(). + The GNUTLS_E_AGAIN should not happen ever, as our sockets are blocking anyway. + But who knows. (That all relies on the fact that GNUTLS_E_INTR and GNUTLS_E_AGAIN + match the EINTR and EAGAIN errno values.) */ + outbytes = gnutls_record_uncork(state->session, 0); + while (outbytes == GNUTLS_E_AGAIN); + if (outbytes < 0) { record_io_error(state, len, US"uncork", NULL); return -1; } + state->corked = FALSE; } #endif